【问题标题】:Why does enable_if_t in template arguments complains about redefinitions?为什么模板参数中的 enable_if_t 抱怨重新定义?
【发布时间】:2015-10-08 15:03:00
【问题描述】:

我有以下使用 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&lt;std::is_same&lt;int, T&gt;::value&gt;&gt;

我想移植我的代码:

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() { }

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

【问题讨论】:

  • 您的第二个代码使用默认模板参数。它们不是函数签名的一部分,因此您要声明两个具有相同签名 = 重新定义的函数模板。 enable_if_t 的对应用法就是 std::enable_if_t&lt;std::is_same&lt;int, T&gt;::value&gt;* = nullptr
  • 嗯,你没有完全重写你的原始代码。你忘了* = nullptr
  • 您可以在其中一个声明中添加一个虚拟模板参数,例如, typename = voidenable_if 之后
  • @dyp:我认为您可以将您的评论作为答案! @KerrekSB:不,这就是enable_if_t @PiotrS 的意义所在。 : 好的
  • @Jean-MichaëlCelerier 你不需要typename 前面的std::enable_if_t。获得更多角色。

标签: c++ templates c++14 sfinae enable-if


【解决方案1】:

让我们删除一些代码。

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&lt;class,class&gt;void() 的模板函数。第二种类型参数具有不同的 default 值这一事实并不重要。这就像期望两个具有不同默认 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() { }

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

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

【讨论】:

    【解决方案2】:

    enable_if_t&lt;B&gt; 只是typename enable_if&lt;B&gt;::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 的情况下,我们有两个函数模板,都带有模板参数&lt;typename, X*&gt;,其中X 的类型依赖第一个模板的类型参数。在g 的情况下,我们有两个带有模板参数&lt;typename, typename&gt; 的函数模板,它只是依赖的默认模板参数,因此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() { }
    

    【讨论】:

    • 如果我能接受多个答案,我也会接受你的答案,因为它同样有效!谢谢!
    • 没问题,Yakk的解释稍微好一点。
    【解决方案3】:

    对于函数返回类型,您正在寻找以下内容:

    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 int\n";
    }
    
    template<typename T>
    std::enable_if_t<std::is_same<float, T>::value, void> foo() {
        std::cout << "foo float\n";
    }
    
    int main() {
        foo<int>();
        foo<float>();
    }
    

    http://ideone.com/TB36gH

    另见

    http://ideone.com/EfLkQy

    【讨论】:

      【解决方案4】:

      你缺少一个 "::type" ..

       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() { }
      

      【讨论】:

      • std::enable_if_tstd::enable_if 的嵌套::type 定义的别名模板
      猜你喜欢
      • 2012-06-29
      • 1970-01-01
      • 2011-12-31
      • 2011-12-14
      • 1970-01-01
      • 2014-08-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多