GCC / CLang对模板模板参数的部分专业化意见不同

时间:2018-10-09 15:57:14

标签: c++ gcc language-lawyer clang++ template-specialization

GCC和clang对此代码有不同意见。

#include <type_traits>

template <typename T, template <typename...> typename Tpl> 
struct storage {
    using type_t = T;

    template <typename... Args>
    using storage_tpl = Tpl<Args...>;
};

template <typename T, template <typename...> typename>
struct F{
    constexpr static int x = 1;
};

template <typename T >
struct F<T, std::void_t>{
    constexpr static int x = 2;
};

int f() {
    using S = storage<int, std::void_t>;

    static_assert(F<int, S::storage_tpl>().x == 2);

    return F<int, S::storage_tpl>().x;
}

根据叮当语S::storage_tpl不是std::void_t;结果,它选择了主模板F而不是部分专业化,从而选择了断言。

乍一看,GCC似乎是正确的,因为它了解嵌套模板只是std::void_t的别名,但它可能太聪明了,标准要求S::storage_tpl和{{1 }}必须是两个不同的模板。

谁是对的?

1 个答案:

答案 0 :(得分:3)

当前似乎尚未指定,h/t to T.C.似乎已被CWG defect report 1286覆盖,它表示:

  

通过更改17.5 [temp.type]中的示例来解决问题1244   来自

的第1段
 template<template<class> class TT> struct X { };
  template<class> struct Y { };
  template<class T> using Z = Y<T>;
  X<Y> y;
  X<Z> z;
     

  template<class T> struct X { };
  template<class> struct Y { };
  template<class T> using Z = Y<T>;
  X<Y<int> > y;
  X<Z<int> > z;
     

实际上,最初的意图是该示例应该是   正确无误;但是,使之成为标准的措辞是   失踪。当前的17.6.7 [temp.alias]措词仅涉及   别名模板的专业化与   替换后的type-id。需要添加措辞,具体说明如下   在什么情况下别名模板本身等效于类   模板。

并提出了以下解决方案:

  

将以下内容作为新段落添加到17.6.7 [temp.alias]之后   第2段:

     

当别名模板声明(称为A)中的type-id由一个simple-template-id组成时,其中template-argument-list   由命名A的每个模板参数的标识符列表组成   完全按照它们在A中出现的顺序排列一次   template-parameter-list,别名模板等效于   如果A和T包含在simple-template-id中命名的模板(称为T)   相同数量的模板参数。 [脚注:此规则是   可传递的:如果别名模板A等效于另一个别名   模板B等效于类模板C,则A也是   等同于C,而A和B也彼此等同。 -结束   脚注] [示例:

  template<typename T, U = T> struct A;

  template<typename V, typename W>
    using B = A<V, W>;                // equivalent to A

  template<typename V, typename W>
    using C = A<V>;                   // not equivalent to A:
                                      // not all parameters used

  template<typename V>
    using D = A<V>;                   // not equivalent to A:
                                      // different number of parameters

  template<typename V, typename W>
    using E = A<W, V>;                // not equivalent to A:
                                      // template-arguments in wrong order

  template<typename V, typename W = int>
    using F = A<V, W>;                // equivalent to A:
                                      // default arguments not considered

  template<typename V, typename W>
    using G = A<V, W>;                // equivalent to A and B

  template<typename V, typename W>
    using H = E<V, W>;                // equivalent to E

  template<typename V, typename W>
    using I = A<V, typename W::type>; // not equivalent to A:
                                      // argument not identifier
     
    

-结束示例]

  

但是此解决方法存在问题,缺陷报告仍处于活动状态。