带decltype(auto)非类型模板参数的类模板偏特化合规性问询
关于decltype(auto)模板参数与auto偏特化的编译器行为分析
先看核心代码:
template <decltype(auto)> struct A { static const int v = 0; }; template <auto n> struct A<n> { static const int v = 1; };
主模板用decltype(auto)作为非类型模板参数,它的推导规则是:传入普通变量名(如i)时,推导类型为decltype(i)(此处是const int);传入带括号的变量(如(i))时,推导类型为decltype((i)(此处是const int&,即引用类型)。
而偏特化版本的auto非类型模板参数,根据C++标准,它只能接受非引用类型的合法字面类型——引用类型无法通过auto推导作为非类型模板参数的类型,因为非类型模板参数的引用类型只能通过显式声明(比如decltype(auto)或const int&)来指定,auto本身不支持推导引用类型。
再看断言部分的行为差异:
const int i = 0; static_assert( A<i>::v == 1 ); //所有编译器均通过 static_assert( A<(i)>::v == 0 );//仅Clang通过
- 对于
A<i>:实参类型是const int,属于auto偏特化能接受的非引用类型,因此匹配偏特化版本,v=1,这部分所有编译器的行为都符合标准。 - 对于
A<(i)>:实参类型是const int&(引用类型),auto偏特化无法匹配引用类型的模板参数,因此只能匹配主模板,v=0。这部分只有Clang的行为符合C++标准,GCC和MSVC错误地将其匹配到偏特化,违反了标准中关于auto非类型模板参数的类型限制。
另外GCC发出的“偏特化未比主模板更特化”的警告也是错误的:偏特化的参数集合是主模板的子集(主模板可接受引用和非引用类型,偏特化仅能接受非引用类型),因此偏特化确实比主模板更特化,符合特化规则。
内容的提问来源于stack exchange,提问作者Fedor
相关产品推荐
相关产品推荐

