【问题标题】:template specialization with default parameters具有默认参数的模板特化
【发布时间】:2014-04-03 04:51:39
【问题描述】:

以下代码编译。任何人都可以解释为什么?我一直在挖掘标准以弄清楚为什么它是合法的。

template <bool B, typename T = void> struct enable_if { };
template <typename T> struct enable_if<true, T> {
    typedef T type;
};
template <typename T, typename Enable = void> struct A;
template <typename T> struct A<T, typename enable_if<(sizeof(T) <= ~0ULL)>::type> {
    void f() { }
};
int main() {
    A<int> a;
    a.f();
}

在声明中:

A<int> a;

由于模板参数“int”只有一个,编译器应该使用主模板,即:

template <typename T, typename Enable = void> struct A;

这是未定义的,因此会导致错误。

【问题讨论】:

  • 不,第二个模板是正确的,因为专业化优先于更通用的定义。顺序在这里并不重要。您有两个空间:通用模板和专用模板。如果可以实例化一个specialized,那么它会被实例化,如果不能,那么将查看泛型。
  • 为什么不直接使用std::enable_if?
  • @texasbruce 一个可能的原因是很多人仍然需要坚持使用 c++98

标签: c++ templates


【解决方案1】:

从 § 14.5.5.1

1 当类模板用于需要 类的实例化,有必要确定是否 实例化将使用主模板或其中之一生成 部分专业。这是通过匹配模板来完成的 带有模板的类模板特化的参数 部分特化的参数列表。

——如果恰好找到一个匹配的特化,则实例化是从 那个专业。

【讨论】:

    【解决方案2】:

    让我们试着弄清楚这里发生了什么:

    // definition of enable_if, second parameter is defaulted to void
    template <bool B, typename T = void> 
    struct enable_if { };
    
    // specialization of enable_if, if first parameter is true, 
    // enable_if has a typedef for the second parameter
    template <typename T> 
    struct enable_if<true, T> {
        typedef T type;
    };
    
    // definition of struct A, second parameter defaults to void
    template <typename T, typename Enable = void> 
    struct A;
    
    // specialization of struct A, second parameter 
    // is obtained from the enable_if::type typedef
    // the first parameter of enable_if is true if the size of T
    // is smaller than the max long long (~0 --> all F)
    template <typename T> 
    struct A<T, typename enable_if<(sizeof(T) <= ~0ULL)>::type> {
        void f() { }
    };
    
    int main() {
        // So we attempt the specialization for struct A<int,enable_if...>
        // The expression of enable_if evaluates to...
        // (sizeof(int) <= ~0ULL) == true
        // ... so it applies the specialization of enable_if<true,void>
        //     (second parameter is void because none is provided, so it 
        //     uses the default.
        // so the enable_if template is valid (selected the specialization)
        // and that means that the struct A<int,enable_if> specialization
        // is valid too, so it is selected.
        A<int> a;
        a.f();
    }
    

    【讨论】:

    • 不不使用第一个 enable_if 因为enable_if&lt;true,void&gt;::type不能扣除。
    • @texasbruce 我的意思是它使用了 enable_if 的特化,因为表达式的计算结果为真。我会澄清
    【解决方案3】:

    当您声明A&lt;int&gt; 时,编译器使用template A&lt;int, enable_if&lt;true&gt;:::type &gt;,因为sizeof(int) &lt;= ~0ULL 的计算结果为true。

    enable_if&lt;true&gt;::type 没有问题,因为编译器可以使用enable_if&lt;true, true&gt;::type。

    【讨论】:

      【解决方案4】:

      当你考虑你的 enable_if 时:

      template <bool B, typename T = void> struct enable_if{ };
      
      template <typename T> struct enable_if<true, T> 
      {
          typedef T type;
      };
      

      在

      void test_EnableIf
      {
       static_assert(
         std::is_same<
           enable_if<(sizeof(int) > 0)>::type,
           void>::value, "test_EnableIf failed." );
      }
      

      结果(类型)是无效的,因为没有指定类型(作为第二 模板参数)。选择 enable_if 的特化 因为布尔表达式为真,而默认 (从主模板中)选择参数,因为没有其他参数 提供,因此类型是无效的,但请注意定义 的类型确实存在(因为选择了专业化)。

      现在,在您对 A 的定义中...

      template <typename T, typename Enable = void> struct A; 
      template <typename T> 
      struct A<T, typename enable_if<
        (sizeof(T) <= ~0ULL)>::type> 
      {
          void f() { } 
      };
      

      ...因为 enable_if 中确实存在 type,所以它是更好的匹配,这会导致选择特化,从而编译。

      相当于同一件事的一个简单的例子如下:

      template <class T, class U = void>
      struct X;
      
      template <class T>
      struct X<T,void>
      {
        static int foo(){ return 0; }
      };
      
      int main()
      {
        return X<int>::foo();
      }
      

      【讨论】:

        猜你喜欢
        • 2018-12-30
        • 2023-03-20
        • 2013-09-13
        • 1970-01-01
        • 1970-01-01
        • 2021-12-31
        • 1970-01-01
        • 1970-01-01
        • 2015-02-04
        相关资源
        最近更新 更多