模板特化和enable_if问题

use*_*855 17 c++ templates sfinae enable-if c++11

我遇到了关于enable_if和模板特化的适当用法的问题.

修改示例后(出于保密原因),这是一个类似的例子:

我有一个名为"less"的函数,用于检查1st arg是否小于2nd arg.假设我想根据输入的类型有两种不同的实现 - 一个是整数实现,另一个是double.

到目前为止我的代码看起来像这样 -

#include <type_traits>
#include <iostream>

template <class T,
          class = typename std::enable_if<std::is_floating_point<T>::value>::type>
     bool less(T a, T b) {
  // ....
}

template <class T,
          class = typename std::enable_if<std::is_integral<T>::value>::type>
     bool less(T a, T b) {
  // ....
}

int main() {
    float a;
    float b;
    less(a,b);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码没有编译,因为 - 它说我正在重新定义less方法.

错误是:

Z.cpp:15:19: error: template parameter redefines default argument
          class = typename std::enable_if<std::is_integral<T>::value>::type>

                  ^
Z.cpp:9:19: note: previous default template argument defined here
          class = typename std::enable_if<std::is_floating_point<T>::value>::type>
                  ^

Z.cpp:16:11: error: redefinition of 'less'
     bool less(T a, T b) {
          ^

Z.cpp:10:11: note: previous definition is here
     bool less(T a, T b) {
          ^

Z.cpp:23:5: error: no matching function for call to 'less'
    less(a,b);
    ^~~~

Z.cpp:15:43: note: candidate template ignored: disabled by 'enable_if'
      [with T = float]
          class = typename std::enable_if<std::is_integral<T>::value>::type>
                                          ^
3 errors generated.
Run Code Online (Sandbox Code Playgroud)

有人能指出这里的错误是什么吗?

Pra*_*ian 23

默认模板参数不是函数模板签名的一部分.因此,在您的示例中,您有两个相同的重载less,这是非法的.clang抱怨重新定义默认参数(根据§14.1/ 12 [temp.param]也是非法的),而gcc产生以下错误信息:

错误:重新定义' template<class T, class> bool less(T, T)'

要修复错误,请将enable_if表达式从default参数移动到虚拟模板参数

template <class T,
          typename std::enable_if<std::is_floating_point<T>::value, int>::type* = nullptr>
     bool less(T a, T b) {
  // ....
}

template <class T,
          typename std::enable_if<std::is_integral<T>::value, int>::type* = nullptr>
     bool less(T a, T b) {
  // ....
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是enable_if在返回类型中使用,但我觉得这更难阅读.

template <class T>
      typename std::enable_if<std::is_floating_point<T>::value, bool>::type 
      less(T a, T b) {
  // ....
}

template <class T>
     typename std::enable_if<std::is_integral<T>::value, bool>::type 
     less(T a, T b) {
  // ....
}
Run Code Online (Sandbox Code Playgroud)

  • 从技术上讲,根据标准,第一组代码格式不正确,因为 `void *` 不是模板非类型参数的有效类型。实际上,据我所知,没有一个编译器真正关心。不过,修复是微不足道的。 (2认同)