enum class enabler{};
template<typename T>
class X {
template<typename std::enable_if<std::is_class<T>::value,enabler>::type = enabler()>
void func();
void func(int a);
void func(std::string b);
};
我有这个类,func
有这3个重载。我需要第二个/第三个版本可用于类/非类类型,第一个版本仅适用于类类型。当我尝试使用上面的enable_if
时,非类类型的类实例化会产生编译错误。
答案 0 :(得分:1)
我不确定你在enabler
找到了什么,但你不能做你正在尝试的事情,因为你的成员函数的声明必须有效,因为T
不是由func
推断出来的。为了实现你想要的额外重载,你可以使用一些适度设计的继承。
struct XBaseImpl {
// whatever you want in both versions
void func(int a) { }
void func(std::string b) { }
};
template <typename, bool> struct XBase;
// is_class is true, contains the extra overload you want
template <typename T>
struct XBase<T, true> : XBaseImpl {
static_assert(std::is_class<T>{}, ""); // just to be safe
using XBaseImpl::func;
void func() { } // class-only
};
// is_class is false
template <typename T>
struct XBase<T, false> : XBaseImpl { };
template<typename T>
class X : public XBase<T, std::is_class<T>{}> { };
答案 1 :(得分:1)
要使SFINAE起作用,必须推导出模板参数。在您的情况下,您尝试实例化T
时已知func
,因此,如果enable_if
条件为false
,而不是SFINAE,则会出现硬错误
要修复错误,只需添加默认值为T
的模板参数,并在enable_if
检查中使用此新参数。现在进行演绎,SFINAE可以为非班级类型提供支持。
template<typename U = T,
typename std::enable_if<std::is_class<U>::value,enabler>::type = enabler()>
void func();
你也不需要专用的enabler
类型,这也适用
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
答案 2 :(得分:0)
您没有启用或禁用某些内容
在一个特定情况下,您只需要编译时错误
因此,您不需要依赖sfinae,static_assert
就足够了。
作为一个最小的工作示例:
#include<string>
template<typename T>
class X {
public:
void func() {
static_assert(std::is_class<T>::value, "!");
// do whatever you want here
}
void func(int a) {}
void func(std::string b) {}
};
int main() {
X<int> x1;
X<std::string> x2;
x2.func(42);
x2.func();
x1.func(42);
// compilation error
// x1.func();
}
一旦SO用户说我:这不是sfinae,这是 - 替换失败总是错误 - 在这种情况下,你应该使用static_assert
而不是。
他是对的,如上例所示,static_assert
比sfinae更易于编写和理解,并且也可以工作。