【问题标题】:Why use SFINAE instead of function overloading?为什么使用 SFINAE 而不是函数重载?
【发布时间】:2020-02-25 14:02:23
【问题描述】:

我正在尝试理解 std::enable_ifcppreference.com 有一个示例,使用它比函数重载有什么优势?

struct T {
    enum { int_t,float_t } m_type;
    template <typename Integer,
              std::enable_if_t<std::is_integral<Integer>::value, int> = 0
    >
    T(Integer) : m_type(int_t) {}
> 
    template <typename Floating,
              std::enable_if_t<std::is_floating_point<Floating>::value, int> = 0
    >
    T(Floating) : m_type(float_t) {} // OK
};


struct T1 {
        enum { int_t, float_t } m_type;
        T1(int) :m_type(int_t)
        {
            cout << "int ctor" << endl;
        }

        T1(float) :m_type(float_t)
        {
            cout << "float ctor" << endl;
        }
    };

【问题讨论】:

  • 您的版本无法处理doublelonglong long...
  • 函数重载仅适用于intfloat。模板适用于int8_tuint8_tint16_tuint16_tint32_tuint32_tint64_tuint64_tfloatdouble
  • 此外,您还接受转换为int(或float)的自定义类型。

标签: c++ sfinae enable-if


【解决方案1】:

你的两个例子不一样。对于第一个示例,该类将完全除任何整数或浮点类型。在您的第二个示例中,您只接受intfloat 意味着如果您传递了long longdouble,那么您有可能会缩小转换范围,这可能会导致您丢失数据。这与您使用的代码无关,但可以而且应该注意它。

在使用可以转换为floatint 的类型时,您也会遇到歧义。例如

T1 foo{0l};

不会编译但是

T foo{0l};

会的。

【讨论】:

  • 示例类不存储实际数据。它存储构造函数是使用整数还是浮点类型调用的。所以没有数据丢失的危险。
  • @Darhuuk 是的。补充说它实际上并不适用于这个例子。
【解决方案2】:

在这种情况下,确实没有真正的优势,因为整数类型将被转换为例如int 首先调用正确的重载构造函数。

但是,假设您想创建一个只接受整数的函数。它应该返回它作为参数接收的整数类型。在这种情况下,手动创建 >10 个重载只是容易出错/愚蠢/烦人/...相反,您可以编写如下内容:

template <typename Integer,
          std::enable_if_t<std::is_integral<Integer>::value, int> = 0>
Integer doMagic (Integer a) {
  return a;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-20
    相关资源
    最近更新 更多