如何解决为什么我应该在函数签名中避免 std::enable_if?

将 hack 放入模板参数 中。

模板参数方法enable_if其他方法至少有两个优点:

  • 可读性 : enable_if 使用和返回/参数类型没有合并到一个杂乱的类型名称消歧器和嵌套类型访问块中;即使可以使用别名模板来减轻消歧器和嵌套类型的混乱,但这仍然会将两个不相关的东西合并在一起。enable_if 的使用与模板参数有关,与返回类型无关。将它们放在模板参数中意味着它们更接近重要的东西;

  • 普遍适用性 :构造函数没有返回类型,并且一些运算符不能有额外的参数,因此其他两个选项都不能应用于任何地方。将 enable_if 放在模板参数中适用于任何地方,因为无论如何您只能在模板上使用 SFINAE。

对我来说,可读性方面是这个选择的最大动力。

解决方法

Scott Meyers 发布了他的下一本书 EC++11
内容和状态。他写道,书中的一项内容可能是 “Avoidstd::enable_ifin function signatures”

std::enable_if可以用作函数参数、返回类型或类模板或函数模板参数,以有条件地从重载决议中删除函数或类。

作为函数参数:

template<typename T>
struct Check1
{
   template<typename U = T>
   U read(typename std::enable_if<
          std::is_same<U,int>::value >::type* = 0) { return 42; }

   template<typename U = T>
   U read(typename std::enable_if<
          std::is_same<U,double>::value >::type* = 0) { return 3.14; }   
};

作为模板参数:

template<typename T>
struct Check2
{
   template<typename U = T,typename std::enable_if<
            std::is_same<U,int>::value,int>::type = 0>
   U read() { return 42; }

   template<typename U = T,double>::value,int>::type = 0>
   U read() { return 3.14; }   
};

作为返回类型:

template<typename T>
struct Check3
{
   template<typename U = T>
   typename std::enable_if<std::is_same<U,U>::type read() {
      return 42;
   }

   template<typename U = T>
   typename std::enable_if<std::is_same<U,U>::type read() {
      return 3.14;
   }   
};
  • 应该首选哪种解决方案,为什么要避免使用其他解决方案?
  • 在哪些情况下, “ 在函数签名中 避免std::enable_if”涉及作为返回类型的使用(这不是正常函数签名的一部分,而是模板特化的一部分)?
  • 成员函数模板和非成员函数模板有什么区别吗?