为什么模板参数中的enable_if_t会抱怨重定义

Why does enable_if_t in template arguments complains about redefinitions?

本文关键字:定义 if 为什么 参数 enable      更新时间:2023-10-16

我有以下使用std::enable_if的情况:

template<typename T,
         typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr>
void f() { }
template<typename T,
         typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr>
void f() { }

现在,我在cppreference中看到了新的语法,在我看来更干净:typename = std::enable_if_t<std::is_same<int, T>::value>>

我想移植我的代码:

template<typename T,
         typename = std::enable_if_t<std::is_same<int, T>::value>>
void g() { }
template<typename T,
         typename = std::enable_if_t<std::is_same<double, T>::value>>
void g() { }

但是现在GCC(5.2)抱怨:

error: redefinition of 'template<class T, class> void g()'
       void g() { }

为什么会这样?在这种情况下,如果可能的话,我该如何做才能获得新的、更简洁的语法呢?

让我们删除一些代码。

template<
  class T,
  class U/* = std::enable_if_t<std::is_same<int, T>::value>*/
 >
void g() { }
template<
  class T,
  class U/* = std::enable_if_t<std::is_same<double, T>::value>*/
 >
void g() { }
如果编译器拒绝了上面两个模板,你会感到惊讶吗?

均为"类型"template<class,class>void()的模板函数。第二个类型参数具有不同的默认值这一事实无关紧要。这就像期望两个具有不同默认int值的不同print(string, int)函数过载一样。;)

第一种情况是:

template<
  typename T,
  typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr
>
void f() { }
template<
  typename T,
  typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr
>
void f() { }

不能删除enable_if子句。更新到enable_if_t:

template<
  class T,
  std::enable_if_t<std::is_same<int, T>::value, int>* = nullptr
>
void f() { }
template<
  class T,
  std::enable_if_t<std::is_same<double, T>::value, int>* = nullptr
>
void f() { }

我还用class代替了typename的使用。我怀疑你的困惑是因为typename有两个含义——一个是作为一种template参数的标记,另一个是作为依赖类型的消歧器。

第二个参数是一个指针,它的类型依赖于第一个参数。如果不首先替换类型T,编译器无法确定这两者是否冲突——您将注意到它们实际上永远不会冲突。

enable_if_t<B>只是typename enable_if<B>::type的别名。让我们把它代入g,这样我们就可以看到fg之间的真正区别:

template<typename T,
         typename std::enable_if<std::is_same<int, T>::value>::type* = nullptr>
void f() { }
template<typename T,
         typename std::enable_if<std::is_same<double, T>::value>::type* = nullptr>
void f() { }
template<typename T,
         typename = typename std::enable_if<std::is_same<int, T>::value>::type>
void g() { }
template<typename T,
         typename = typename std::enable_if<std::is_same<double, T>::value>::type>
void g() { }
f的例子中,我们有两个函数模板,它们都带有模板形参<typename, X*>,其中X的类型依赖于第一个模板实参的类型。在g的例子中,我们有两个带有模板形参<typename, typename>的函数模板,并且只有默认模板实参是相互依赖的,因此c++认为它们都声明了同一个实体。

任何一种样式都可以与enable_if_t别名一起使用:

template<typename T,
         std::enable_if_t<std::is_same<int, T>::value>* = nullptr>
void f() { }
template<typename T,
         std::enable_if_t<std::is_same<double, T>::value>* = nullptr>
void f() { }
template<typename T,
         typename = std::enable_if_t<std::is_same<int, T>::value>>
void g() { }
template<typename T,
         typename = std::enable_if_t<std::is_same<double, T>::value>>
void g() { }

对于函数返回类型,您要查找以下内容:

template<typename T> std::enable_if_t< conditional, instantiation result > foo();

的例子:

#include <iostream>
// when T is "int", replace with 'void foo()'   
template<typename T>
std::enable_if_t<std::is_same<int, T>::value, void> foo() {
    std::cout << "foo intn";
}
template<typename T>
std::enable_if_t<std::is_same<float, T>::value, void> foo() {
    std::cout << "foo floatn";
}
int main() {
    foo<int>();
    foo<float>();
}
http://ideone.com/TB36gH

参见

http://ideone.com/EfLkQy

你失踪"::". .

 template<typename T,
             typename = std::enable_if_t<std::is_same<int, T>::value>::type>
    void g() { }
    template<typename T,
             typename = std::enable_if_t<std::is_same<double, T>::value>::type>
    void g() { }