C++ 如何在重载时使用enable_ enum类启用码{}; 模板 X类{ 模板 void func(); 无效函数(int a); void func(标准::字符串b); };
我为C++ 如何在重载时使用enable_ enum类启用码{}; 模板 X类{ 模板 void func(); 无效函数(int a); void func(标准::字符串b); };,c++,templates,c++11,sfinae,enable-if,C++,Templates,C++11,Sfinae,Enable If,我为func使用了这3个重载的类。我需要第二个/第三个版本对类/非类类型都可用,并且第一个版本仅对类类型可用。当我尝试如上所述使用enable\u if时,非类类型的类实例化会产生编译错误。我不太确定使用enable的目的是什么,但是您无法执行您正在尝试的操作,因为成员函数的声明必须有效,因为t不是由func推导出来的。为了实现添加额外重载的目的,可以使用一些适度人为的继承 enum class enabler{}; template<typename T> class X {
func
使用了这3个重载的类。我需要第二个/第三个版本对类/非类类型都可用,并且第一个版本仅对类类型可用。当我尝试如上所述使用enable\u if
时,非类类型的类实例化会产生编译错误。我不太确定使用enable
的目的是什么,但是您无法执行您正在尝试的操作,因为成员函数的声明必须有效,因为t
不是由func
推导出来的。为了实现添加额外重载的目的,可以使用一些适度人为的继承
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);
};
struct XBaseImpl{
//两个版本都有你想要的
void func(int a){}
void func(std::string b){}
};
模板结构XBase;
//is_类为true,包含所需的额外重载
模板
结构XBase:XBaseImpl{
静态_断言(std::is_类{},“”;//为了安全起见
使用XBaseImpl::func;
void func(){}//仅限类
};
//你的课是假的吗
模板
结构XBase:XBaseImpl{};
模板
X类:公共XBase{};
若要工作,必须推导模板参数。在您的情况下,T
在您尝试实例化func
时已经是已知的,因此如果enable\u if
条件为false
,而不是SFINAE,您将得到一个硬错误
要修复此错误,只需添加一个默认值为T
的模板参数,并在enable\u if
检查中使用此新参数。现在发生了扣减,SFINAE可以对非类类型生效
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>{}> { };
您没有启用或禁用某些内容。
您只需要在特定情况下出现编译时错误。
因为您不需要依赖sfinae,所以一个
静态断言就足够了
作为一个最低限度的工作示例:
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
#包括
模板
X类{
公众:
void func(){
静态_断言(std::is_class::value,“!”;
//在这里你想干什么就干什么
}
void func(int a){}
void func(std::string b){}
};
int main(){
x1;
x2;
x2.func(42);
x2.func();
x1.func(42);
//编译错误
//x1.func();
}
曾经有一位SO用户对我说:这不是sfinae,这是-替换失败总是一个错误-在这种情况下,您应该使用静态断言
。
他是对的,如上面的例子所示,static\u assert
比sfinae更容易编写和理解,而且它也能工作。sfinae只适用于推导类型。你能详细说明一下吗?你实际上不需要使用sfinae。在您的情况下,一个静态断言就足够了。请参阅我(晚些时候)回答中的最小示例。@skypjack True,如果这不是一个简化示例的话。在非简化版本中,它可能会影响其他函数的重载解析。这种方法的缺点是,您可以使用显式模板参数运行func()
:func()
将导致类重载,即使T
不是class@AndreiR. 是的,如果你想射中自己的脚,你总能找到办法。@Praetorian你仍然可以使用守卫参数包,比如template void func()代码>。显式模板参数将被删除。@mkmostafa我拒绝了编辑,因为我认为您试图防止人们显式地为func
指定模板参数,而该编辑并不能解决问题。这样做将再次意味着没有演绎,SFINAE将不会发生,并且当条件为false时,您将得到一个硬错误。@skypjack当然,这有点好,但仍然令人惊讶,因为用户提供的模板参数没有任何效果。我认为像上面的例子这样的函数应该被记录下来,以警告用户不要指定模板参数,然后让他们做他们想做的事情。
template<typename U = T,
typename std::enable_if<std::is_class<U>::value, int>::type* = nullptr>
void func();
#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();
}