Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ SFINAE重载,必须考虑哪些规则_C++_Templates_C++14_Sfinae - Fatal编程技术网

C++ SFINAE重载,必须考虑哪些规则

C++ SFINAE重载,必须考虑哪些规则,c++,templates,c++14,sfinae,C++,Templates,C++14,Sfinae,我不知道使用SFINAE来实现方法重载必须考虑哪些规则。我多次遇到问题,因为据我所知,需要更多的规则。因此,我希望有一套可以简单解释的规则,以帮助解决一般问题,而不是一次又一次地提出问题 我的出发点是: 代码1 class AA { public: using TRAIT = int; }; class BB { public: using TRAIT = float; }; template < typename T> class Y { public:

我不知道使用SFINAE来实现方法重载必须考虑哪些规则。我多次遇到问题,因为据我所知,需要更多的规则。因此,我希望有一套可以简单解释的规则,以帮助解决一般问题,而不是一次又一次地提出问题

我的出发点是:

代码1

class AA { public: using TRAIT = int; };
class BB { public: using TRAIT = float; };

template < typename T>
class Y
{   
    public:
        template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
            Y( ) { std::cout << "First" << std::endl; }

        template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
            Y( ) { std::cout << "Second" << std::endl; }

};
class AA{public:使用TRAIT=int;};
类BB{public:使用TRAIT=float;};
模板
Y类
{   
公众:
模板::值,int>::类型>
Y(){std::cout
Y(){std::cout::type,typename X=int>
Y(X*=nullptr){std::cout
Y(){std::cout::type>
Y(int*=nullptr){std::cout

Y(){std::cout函数的签名应该不同,默认值(对于模板和常规参数)不是签名的一部分

template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
Y();

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y();
模板::值,int>::类型>
Y();
模板::值,浮点>::类型>
Y();
只是

template <typename U, typename V>
Y();

template <typename U, typename V>
Y();
模板
Y();
模板
Y();
所以,重新定义

鉴于

template <typename U = T, typename V = typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type, typename X=int>
Y( X* = nullptr);

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( );
template::value,int>::type,typename X=int>
Y(X*=nullptr);
模板::值,浮点>::类型>
Y();

模板
Y(X*);
模板
Y();
所以不同的签名

避免总是添加参数的一种方法是执行以下操作

template <typename U = T, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type* = nullptr>
Y();

template <typename U = T, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type* = nullptr>
Y();
模板
Y();
模板::类型*=nullptr>
Y();
这会导致不同的签名:

template <typename U, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type*>
Y();

template <typename U, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type*>
Y();
模板
Y();
模板::类型*>
Y();

函数的签名应该不同,默认值(对于模板和常规参数)不是签名的一部分。所以

template <typename U = T, typename V= typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type>
Y();

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y();
模板::值,int>::类型>
Y();
模板::值,浮点>::类型>
Y();
只是

template <typename U, typename V>
Y();

template <typename U, typename V>
Y();
模板
Y();
模板
Y();
所以,重新定义

鉴于

template <typename U = T, typename V = typename std::enable_if< std::is_same< int, typename U::TRAIT>::value, int >::type, typename X=int>
Y( X* = nullptr);

template <typename U = T, typename V= typename std::enable_if< !std::is_same< int, typename U::TRAIT>::value, float >::type>
Y( );
template::value,int>::type,typename X=int>
Y(X*=nullptr);
模板::值,浮点>::类型>
Y();

模板
Y(X*);
模板
Y();
所以不同的签名

避免总是添加参数的一种方法是执行以下操作

template <typename U = T, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type* = nullptr>
Y();

template <typename U = T, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type* = nullptr>
Y();
模板
Y();
模板::类型*=nullptr>
Y();
这会导致不同的签名:

template <typename U, typename std::enable_if<std::is_same<int, typename U::TRAIT>::value>::type*>
Y();

template <typename U, typename std::enable_if<!std::is_same<int, typename U::TRAIT>::value>::type*>
Y();
模板
Y();
模板::类型*>
Y();

“我认为SFINAE是通过实例化构造函数模板来实现的,并且只有一个构造函数可用。这不是事实!”=>但即使没有AA或BB的定义,也会出现错误。因此,问题与模板实例化无关。重复已经说过的话:这就像
void foo一样(bool b=false)
void foo(bool b=true)
不能在定义中共存,仅仅因为它们有不同的默认值。
“我认为SFINAE是通过实例化构造函数模板实现的,只有一个构造函数可用。这不是事实!”=>但即使没有AA或BB的定义,也会出现错误。因此,问题与模板实例化无关。重复已经说过的内容:这就像如何
void foo(bool b=false)
void foo(bool b=true)
不能仅仅因为它们有不同的默认值而在定义中共存。
也是如此。最后一个例子是“简单”使用默认的初始化类型指针对我来说很奇怪。我认为这最终会出现在
模板中,这两个定义也是一样的。你能补充一个简短的解释吗?为什么签名会在这里用SFINAE构造的完整表达式展开?@Klauss,即使
std::enable\u if.
导致
void*
对于两者,它是不同的签名(之前)。但是如果它们都导致一些
T
void*
,那么无论如何您都会有不明确的调用。因此,应该仔细选择条件(一些写入
禁用\u if
helper在两者中写入相同的条件)@Klauss在第一次看到这个东西时,我认为插入一个
static\u断言(std::is\u same::value,“无法显式参数化模板”)是有用的;
只是为了认识到在调用中有一定程度的自由,你不想让人们使用它,来覆盖为SFINAE抛出的默认值U=t(尽管具体来说,你是这样做的。)因此,例如
Y yaa;yaa.foo()
@HostileFork:构造函数不需要
静态断言
,因为用户无法为构造函数指定模板参数。最后一个示例是“简单”使用默认的初始化类型指针对我来说很奇怪。我认为这最终会出现在
模板中,这两个定义也是一样的。你能补充一个简短的解释吗?为什么签名会在这里用SFINAE构造的完整表达式展开?@Klauss,即使
std::enable\u if.
导致
void*
对于两者,它是不同的签名(之前)。但是如果它们都导致一些
T
void*
,那么无论如何您都会有不明确的调用。因此,应该仔细选择条件(一些写入
禁用\u if
helper在两者中写入相同的条件)@Klauss在第一次看到这个东西时,我认为插入一个
static\u断言(std::is\u same::value,“无法显式参数化模板”)是有用的;
只是为了认识到在调用中有一定程度的自由,你不想让人们使用它,来覆盖为SFINAE抛出的默认值U=t(尽管具体来说,你是这样做的。)因此,例如
Y yaa;yaa.foo();
@HostileFork:构造函数不需要
静态断言
,因为用户无法为构造函数指定模板参数。