非类型模板参数特化时GCC、Clang、MSVC编译行为不一致,哪方符合C++标准?
结论
Clang与MSVC的行为符合C++标准,GCC存在不符合标准的实现偏差。
原因分析
我们先明确两个编译场景的差异:
- 开启(A)开关时,宏
GCC_CONST展开为const,MyType的偏特化匹配目标为const sized_t2<col_size, val>类型 - 关闭(A)开关时,宏
GCC_CONST展开为空,MyType的偏特化匹配目标为无cv限定的sized_t2<col_size, val>类型
接下来看模板参数推导的核心规则:
Test2的模板参数Cols是类类型的非类型模板参数(C++20特性),decltype(Cols)返回的是该模板参数的声明类型,也就是无顶层const的sized_t2<...>类型。- 模板偏特化的类型匹配过程中,顶层cv限定符是类型的有效组成部分,不会被自动忽略:只有当传入的模板实参类型和偏特化的模式类型完全匹配时,偏特化才会被选中。
对应两个场景的验证:
- 关闭(A)开关时,偏特化模式是无cv限定的
sized_t2<...>,和decltype(Cols)的类型完全匹配,因此Clang、MSVC可以正常编译,符合标准;此时GCC无法匹配特化,属于实现错误。 - 开启(A)开关时,偏特化模式是
const sized_t2<...>,和无cv限定的实参类型不匹配,因此Clang、MSVC无法找到特化,符合标准;此时GCC可以正常编译,是因为它错误地给decltype(Cols)的结果添加了顶层const,属于实现偏差。
复现代码
#include <tuple> #include <cstddef> template <std::size_t col_size, auto val> struct sized_t2 { // static constexpr std::size_t size = col_size; // static constexpr auto value = val; using type = decltype(val); }; template <typename> struct MyType; /* // (A) #define GCC_CONST const /*/ #define GCC_CONST //*/ template <std::size_t col_size, auto val> struct MyType<GCC_CONST sized_t2<col_size, val>> { using type = int; }; template<sized_t2... Cols> auto Test2() { using XXX = std::tuple<typename MyType<decltype(Cols)>::type...>; (void)XXX{}; return; } int main() { struct x{}; Test2<sized_t2<42,x{}>{}>(); }
内容的提问来源于stack exchange,提问作者OwnageIsMagic
相关产品推荐
相关产品推荐

