为什么我应该在函数签名中避免 std::enable_if

2021-12-13 00:00:00 templates c++ c++11 sfinae enable-if

Scott Meyers 发布了内容和状态他的下一本书 EC++11.他写道,书中的一项可能是避免在函数签名中使用std::enable_if".

Scott Meyers posted content and status of his next book EC++11. He wrote that one item in the book could be "Avoid std::enable_if in function signatures".

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

std::enable_if can be used as a function argument, as a return type or as a class template or function template parameter to conditionally remove functions or classes from overload resolution.

在这个问题中显示了所有三个解决方案.

In this question all three solution are shown.

作为函数参数:

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, typename std::enable_if<
            std::is_same<U, 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, int>::value, U>::type read() {
      return 42;
   }

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

  • 应该首选哪种解决方案,为什么我应该避免使用其他解决方案?
  • 在哪些情况下避免在函数签名中使用 std::enable_if" 涉及作为返回类型的使用(它不是普通函数签名的一部分,而是模板特化的一部分)?
  • 成员函数模板和非成员函数模板有什么区别吗?
  • 推荐答案

    将 hack 放入模板参数.

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

    The enable_if on template parameter approach has at least two advantages over the others:

    • 可读性:enable_if 的使用和返回/参数类型没有合并成一大块类型名称消歧器和嵌套类型访问;尽管可以使用别名模板减轻消歧器和嵌套类型的混乱,但这仍然会将两个不相关的东西合并在一起.enable_if 的使用与模板参数有关,而不是与返回类型有关.将它们包含在模板参数中意味着它们更接近重要的内容;

    • readability: the enable_if use and the return/argument types are not merged together into one messy chunk of typename disambiguators and nested type accesses; even though the clutter of the disambiguator and nested type can be mitigated with alias templates, that would still merge two unrelated things together. The enable_if use is related to the template parameters not to the return types. Having them in the template parameters means they are closer to what matters;

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

    universal applicability: constructors don't have return types, and some operators cannot have extra arguments, so neither of the other two options can be applied everywhere. Putting enable_if in a template parameter works everywhere since you can only use SFINAE on templates anyway.

    对我来说,可读性是这个选择的重要推动因素.

    For me, the readability aspect is the big motivating factor in this choice.

相关文章