C ++ enable_if可以有默认实现吗?

时间:2016-03-19 05:40:11

标签: c++ templates

我想编写一个函数print,根据其参数的类型,它的行为会有所不同。

这是我的实施:

template <typename T, typename std::enable_if<std::is_array<T>::value, int>::type = 0>
void print(const T &v) {
  std::cout << "array: ";
  for (const auto &e : v) {
    std::cout << e << ", ";
  }
  std::cout << std::endl;
}

template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void print(const T &v) {
  std::cout << "integral: " << v << std::endl;
}

template <typename T, typename std::enable_if<!(std::is_array<T>::value || std::is_integral<T>::value), int>::type = 0>
void print(const T &v) {
  std::cout << "default: " << v << std::endl;
}

此代码按预期工作,但最后一个规范中的条件过于复杂。

有没有解决方案来简化最后一个?

2 个答案:

答案 0 :(得分:4)

您可以用于默认情况的一般方法是使用一个带有变量参数列表的函数。只有在没有其他功能匹配时才会使用此选项。这是一个例子:

template <typename T, typename std::enable_if<std::is_array<T>::value, int>::type = 0>
void print_helper(const T &v,int) {
  std::cout << "array: ";
  for (const auto &e : v) {
    std::cout << e << ", ";
  }
  std::cout << std::endl;
}

template <typename T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
void print_helper(const T &v,int) {
  std::cout << "integral: " << v << std::endl;
}

template <typename T>
void print_helper(const T &v,...) {
  std::cout << "default: " << v << std::endl;
}

template <typename T>
void print(const T &v)
{
  print_helper(v,0);
}

对于只有两个重载,额外的功能可能不值得,但是当你得到更多的重载时,这个表单确实可以为默认情况付出代价。

答案 1 :(得分:1)

我们可以使用额外的选择器为我们做得更好,Xeo提供:

struct otherwise{ otherwise(...){} };

template<unsigned I>
struct choice : choice<I+1>{};

// terminate recursive inheritence at a convenient point,
// large enough to cover all cases
template<> struct choice<10>{};

然后我们选择列表中的每个排名都会优先于下一个排名,我们只需要在我们开始时停用:

// just forward to our first choice
template <class T> void print(const T &v) { print(v, choice<0>{}); }

我们的首选是阵列:

template <class T, class = std::enable_if_t<std::is_array<T>::value>>
void print(const T& v, choice<0> ) { ... }

然后积分:

template <class T, class = std::enable_if_t<std::is_integral<T>::value>>
void print(const T& v, choice<1> ) { ... }

然后是任何事情

template <class T>
void print(const T& v, otherwise ) { ... }

这种结构允许任意多种选择。