我试图了解SFINAE,在尝试将其应用于模板类成员函数时遇到了一个问题。感谢Why dons';SFINAE(enable_if(是否适用于类模板的成员函数?我能够设置一个基本示例(在线运行(:
template<typename T>
class Foo{
public:
template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
void sfinae() { // Foo<anything else>
std::cout << "sfinae default" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
void sfinae() { // Foo<int>
std::cout << "sfinae int" << std::endl;
}
template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
void sfinae() { // Foo<float>
std::cout << "sfinae float" << std::endl;
}
};
我有两个后续问题:
1如何分离成员函数的声明和定义
我尝试了以下定义:
template <typename T>
template <typename U = T, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int> = 0>
void Foo<T>::sfinae() { // Foo<anything else>
std::cout << "sfinae default" << std::endl;
}
但这会导致编译错误
2.catch-all默认情况(打印sfinae默认情况(当前必须写为not(type1, type2,...)
,这可能是巨大的。是否有更短/更清洁的解决方案
编辑:根据@Jans的回答,这里有一个更正的解决方案。
在行外定义中,您删除了默认参数,它们取自声明:
template <class T>
template <typename U, typename std::enable_if_t<!std::is_same<U, int>::value && !std::is_same<U, float>::value,int>>
void Foo<T>::sfinae() { // Foo<anything else>
std::cout << "sfinae default" << std::endl;
}
其他也是如此
catch-all默认情况(打印sfinae默认情况(当前必须写为
not(type1, type2,...)
,这可能是巨大的。是否有更短/更清洁的解决方案?
为此,您需要添加一个额外的参数来对重载进行排名,为catch-all提供最低排名。这通常是使用省略号参数并不比任何其他参数类型更好的事实来完成的:
template <typename U = T>
void sfinae(...);
template <typename U = T, typename std::enable_if_t<std::is_same<U, int>::value,int> = 0>
void sfinae(int);
template <typename U = T, typename std::enable_if_t<std::is_same<U, float>::value,int> = 0>
void sfinae(int);
Foo<char>{}.sfinae(0); // select the catch-all
这意味着,由于...
比任何其他参数都差(int
比...
好(,因此只有当其他两个参数不能调用时,即如果它们是SFINAE时,才考虑过载sfinae(...)
。