SFINAE 重载,必须考虑哪些规则
SFINAE overloading, which rules must considered
我不知道必须考虑哪些规则才能使用 SFINAE 进行方法重载。我 运行 多次遇到问题,因为据我所知,接缝处涉及更多规则。所以我希望有一套可以简明扼要地解释的规则,以帮助解决一般性问题,而不是一遍又一遍地问问题。
我的出发点在这里:
Specializing class with SFINAE if a parameter pack is needed
代码 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; }
};
error: 'template template Y::Y()' cannot be overloaded
对于这个问题我得到了评论:
"the "constructor cannot be overloaded" problem can be solved by adding a dummy and defaulted template parameter (like , typename Z = void) to one of the constructors"
好的,将我的代码更改为:
代码 2
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, typename X=int>
Y( X* = nullptr) { 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; }
};
OK,编译通过。但是简化接缝的工作也让我怀疑。
代码 3
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( int* = nullptr) { 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; }
};
最后一个例子也可以!它在其中一个构造函数中有一个默认参数,但这个参数不是模板化参数。
对我来说,现在很不清楚哪些规则在背后起作用,以便将事情运行这里。
我的第一个误解是,我认为 SFINAE 是通过实例化构造函数模板来实现的,并且只有一个构造函数可用。这不是事实!所有构造函数的每个参数集必须不同!?为什么?此外,为什么它应该或必须是模板化参数?我的示例 3 接缝可以工作,但其他人给了我使用 dummy and defaulted template parameter (like , typename Z = void)
的建议。有人可以给我一些关于这个主题的背景信息吗?
函数的签名应该不同,默认值(对于模板和常规参数)不是签名的一部分。所以
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();
简直就是
template <typename U, typename V>
Y();
template <typename U, typename V>
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 <typename U, typename V, typename X>
Y(X*);
template <typename U, typename V>
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();
这导致不同的签名:
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();
我不知道必须考虑哪些规则才能使用 SFINAE 进行方法重载。我 运行 多次遇到问题,因为据我所知,接缝处涉及更多规则。所以我希望有一套可以简明扼要地解释的规则,以帮助解决一般性问题,而不是一遍又一遍地问问题。
我的出发点在这里: Specializing class with SFINAE if a parameter pack is needed
代码 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; }
};
error: 'template template Y::Y()' cannot be overloaded
对于这个问题我得到了评论:
"the "constructor cannot be overloaded" problem can be solved by adding a dummy and defaulted template parameter (like , typename Z = void) to one of the constructors"
好的,将我的代码更改为:
代码 2
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, typename X=int>
Y( X* = nullptr) { 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; }
};
OK,编译通过。但是简化接缝的工作也让我怀疑。
代码 3
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( int* = nullptr) { 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; }
};
最后一个例子也可以!它在其中一个构造函数中有一个默认参数,但这个参数不是模板化参数。
对我来说,现在很不清楚哪些规则在背后起作用,以便将事情运行这里。
我的第一个误解是,我认为 SFINAE 是通过实例化构造函数模板来实现的,并且只有一个构造函数可用。这不是事实!所有构造函数的每个参数集必须不同!?为什么?此外,为什么它应该或必须是模板化参数?我的示例 3 接缝可以工作,但其他人给了我使用 dummy and defaulted template parameter (like , typename Z = void)
的建议。有人可以给我一些关于这个主题的背景信息吗?
函数的签名应该不同,默认值(对于模板和常规参数)不是签名的一部分。所以
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();
简直就是
template <typename U, typename V>
Y();
template <typename U, typename V>
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 <typename U, typename V, typename X>
Y(X*);
template <typename U, typename V>
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();
这导致不同的签名:
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();