如何使用enable_if与重载

时间:2016-08-12 00:55:18

标签: c++ templates c++11 sfinae enable-if

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时,非类类型的类实例化会产生编译错误。

3 个答案:

答案 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更易于编写和理解,并且也可以工作。