#ifndef _NANXING_CHECK_OPERATOR_H_
#define _NANXING_CHECK_OPERATOR_H_
#include<type_traits>
//这个文件的目的是为了做一些匹配性检查,检查一些泛型的实例化是否能满足一定的要求
//使用SFINAE
//这个头文件的操作需要编译器至少支持C++11才能用,但是在C++20中引入的约束模板类型已经成功的将这些抽象的操作加入语法中
//由于到目前(2024年10月还有部分编译器的默认支持不是C++20,因此还是保留这个文件)
//当然目前libstdc++中模板的判断还是用类似的方法

#define NANXING_TYPETRAIT_TEMPLATE_T_V_ template<typename T ,typename V =void >
#define NANXING_TYPETRAIT_TEMPLATE_T_ template<typename T > 
#define NANXING_BASIC_OPERATOR_(Type, Op) nanxing::Op##_admit<Type>::value   //注意要写成这样才行
namespace nanxing{
    template<typename...>         //这里用泛型的作用在于为了后面做模板参数匹配
    using void_t=void;

    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct add_admit:std::false_type{static void p(){std::cout<<"false"<<std::endl;}};                //基础模板类型


    //关于这里需要使用void_t修饰,这个是这样的
    //这里实际上是做了一个偏特化,将V进行特化,特化为void_t<decltype(std::declval<T>()+std::declval<T>())>
    //当我们使用的时候我们实际上是只传入了一个参数,第二个参数使用默认值void,当且仅当偏特化的特化值为void的时候才能成功匹配
    //看下面这个例子即可

    // template<typename T,typename V=void>
    // struct test{static const int value=0;};
    // template<typename T>
    // struct test<T,void>{static const int value=1;};

    //T能否进行加法运算
    NANXING_TYPETRAIT_TEMPLATE_T_
    struct add_admit<T,void_t<decltype(std::declval<T>()+std::declval<T>())>>:std::true_type{static void p(){std::cout<<"true"<<std::endl;}};

    //T能否进行减法运算
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct mut_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct mut_admit<T,void_t<decltype(std::declval<T>()-std::declval<T>())>>:std::true_type{};

    //T能否进行比较
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct compare_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct compare_admit<T,void_t<decltype(std::declval<T>()<std::declval<T>())>>:std::true_type{};

    //T能否相互赋值
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct equal_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct equal_admit<T,void_t<decltype(std::declval<T>()=std::declval<T>())>>:std::true_type{};

    //T能否下标运算
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct index_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct index_admit<T,void_t<decltype(std::declval<T>()[0])>>:std::true_type{};    

    //T指向的数据能否进行比较运算
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct compare_ptr_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct compare_ptr_admit<T,void_t<decltype(std::declval<T>()[0]==std::declval<T>()[0])>>:std::true_type{};

    //T指向的数据能否相互赋值
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct equal_ptr_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct equal_ptr_admit<T,void_t<decltype(std::declval<T>()[0]=std::declval<T>()[0])>>:std::true_type{};

    //T类型可以作为可调用对象进行调用
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct fun_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct fun_admit<T,void_t<decltype(std::declval<T>()())>>:std::true_type{};
    

    //T类型允许从一个T类型的实例构造(即拷贝构造)
    NANXING_TYPETRAIT_TEMPLATE_T_V_
    struct copy_construct_admit:std::false_type{};

    NANXING_TYPETRAIT_TEMPLATE_T_
    struct copy_construct_admit<T,void_t<decltype(T(std::declval<T>(T)))>>:std::true_type{};      
    //接下去用另一种技术实现函数存在性的判定
    //用函数的模板匹配


}
#endif