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();
}