基于不同枚举值的类成员重载(或特化)

Jes*_*Jes 3 c++ templates sfinae enable-if c++11

是否可以根据给定的枚举值重载或专门化类成员函数?

enum class Type {
  TypeA,
  TypeB,
  TypeC
};

class Foo {

  public:

  template <Type t, typename R = std::enable_if_t<t==Type::TypeA, int>>
  R get() {
    return 1;
  }

  template <Type t, typename R = std::enable_if_t<t==Type::TypeB, double>>
  R get() {
    return 2;
  }

  template <Type t, typename R= std::enable_if_t<t==Type::TypeC, float>>
  R get() {
    return 3;
  }
};

Foo foo;

std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;
Run Code Online (Sandbox Code Playgroud)

编译抱怨上面的代码片段重载.

Chr*_*eck 5

修复它的一种非常标准的方法是将std::enable_if子句放在函数的返回类型中,而不是像这样的模板参数中.

这符合c ++ 11标准编译.

#include <iostream>
#include <type_traits>

enum class Type {
  TypeA,
  TypeB,
  TypeC
};

class Foo {

  public:

  template <Type t>
  typename std::enable_if<t==Type::TypeA, int>::type get() {
    return 1;
  }

  template <Type t>
  typename std::enable_if<t==Type::TypeB, double>::type get() {
    return 2;
  }

  template <Type t>
  typename std::enable_if<t==Type::TypeC, float>::type get() {
    return 3;
  }
};

static_assert(std::is_same<int, decltype( std::declval<Foo>().get<Type::TypeA>())>::value, "");
static_assert(std::is_same<double, decltype( std::declval<Foo>().get<Type::TypeB>())>::value, "");
static_assert(std::is_same<float, decltype( std::declval<Foo>().get<Type::TypeC>())>::value, "");

int main() {

Foo foo;

std::cout << foo.get<Type::TypeA>() << std::endl;
std::cout << foo.get<Type::TypeB>() << std::endl;
std::cout << foo.get<Type::TypeC>() << std::endl;

}
Run Code Online (Sandbox Code Playgroud)

我不确定我是否可以详细解释为什么这种变化会对编译器产生如此大的影响.

但是,请考虑以下内容.对于您的版本,虽然您实际上从未实际get使用两个显式模板参数进行实例化,但从技术上讲,这三个成员函数模板都可以"碰撞"并生成具有完全相同名称的函数.因为,如果你实例化了get<Type::TypeB, int>,那么它将具有相同的返回类型,输入参数和名称get<Type::TypeA>.C++不支持函数模板特化,它会使重载决策规则变得非常复杂.因此,具有可能碰撞的功能模板会使编译器非常不安.

当你按照我展示的方式进行时,模板不可能碰撞并生成具有相同名称和签名的函数.