递归变量模板特化(及MSVC行为):foo<list<int,double>>类型判定
问题分析与解答
代码回顾
给定代码如下:
template <typename...> struct list{}; template <typename> list<> foo{}; template <typename H, typename... Ts> list<H, decltype(foo<list<Ts...>>)> foo<list<H, Ts...>>{};
问题1:代码是否符合C++20标准,目标类型是否有明确定义?
这段代码符合C++20标准,且foo<list<int, double>>的类型有明确的定义。
理由如下:
- C++标准允许模板的递归实例化,只要存在明确的终止条件。这里的递归终止于
Ts为空参数包的场景:当Ts为空时,list<Ts...>即list<>,此时会匹配主模板template <typename> list<> foo{},得到类型list<>,递归流程终止。 - 完整推导逻辑清晰可追溯:
- 实例化
foo<list<int, double>>时,匹配特化模板,H=int,Ts={double},因此其类型为list<int, decltype(foo<list<double>>)>。 - 实例化
foo<list<double>>时,匹配特化模板,H=double,Ts={},因此其类型为list<double, decltype(foo<list<>>)>。 - 实例化
foo<list<>>时,匹配主模板,类型为list<>。 - 回溯推导结果:
foo<list<double>>的类型是list<double, list<>>,进而foo<list<int, double>>的类型为list<int, list<double, list<>>>。
- 实例化
问题2:哪个编译器的行为是正确的?
GCC 13、Clang 16、ICX 2023.2的行为符合标准,是正确的;MSVC(v19.37)的行为不符合标准。
MSVC的错误在于,推导decltype(foo<list<double>>)时未正确匹配特化模板,错误地将foo<list<double>>的类型推导为list<>(直接匹配主模板),最终导致foo<list<int, double>>的类型错误地成为list<int, list<>>。而其他编译器正确执行了递归特化推导,得到了符合标准定义的类型。
内容的提问来源于stack exchange,提问作者rm -rf
相关产品推荐
相关产品推荐

