C++20模板推导分歧:b{d{}}构造的编译器行为差异咨询
C++20模板构造函数约束与类模板推导的编译器分歧解析
问题描述
我认为b{d{}}的构造应触发编译错误,因为b的模板构造函数受约束限制不可行。但GCC和MSVC接受该代码,推导b为b<int>而非b<d>,这与我理解的隐式推导指南template<typename T> b(T) -> b<T>不符。请问应信任哪个编译器?C++20标准对此行为有何规定?
代码示例
template<typename T> struct b { b() = default; b(T) requires false {} }; struct d : b<int> {}; inline constexpr auto z = b{d{}};
Clang报错信息
<source>:7:27: error: no matching constructor for initialization of 'b<d>' 7 | inline constexpr auto z = b{d{}}; | ^~~~~~ <source>:2:8: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'd' to 'const b<d>' for 1st argument 2 | struct b { | ^ <source>:2:8: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'd' to 'b<d>' for 1st argument 2 | struct b { | ^ <source>:4:5: note: candidate constructor not viable: constraints not satisfied 4 | b(T) requires false {} | ^ <source>:4:19: note: because 'false' evaluated to false 4 | b(T) requires false {} | ^ <source>:3:5: note: candidate constructor not viable: requires 0 arguments, but 1 was provided 3 | b() = default; | ^
解答
编译器正确性判定
GCC和MSVC的行为符合C++20标准,Clang在此场景下存在实现错误。
标准依据与行为解释
C++20标准中,类模板推导(CTAD)的候选函数集不仅包含用户定义构造函数对应的隐式推导指南,还包括类模板特化的隐式生成构造函数(如拷贝、移动构造函数)对应的推导指南:
- 对于
b<T>的隐式拷贝构造函数b(const b<T>&),会生成对应的隐式推导指南:template<typename T> b(const b<T>&) -> b<T>。 - 当用
d{}初始化b实例时,d作为b<int>的派生类,可以隐式转换为const b<int>&,因此上述拷贝构造函数对应的推导指南会推导出T=int。 b<int>的拷贝构造函数不受requires false约束(该约束仅作用于用户定义的b(T)构造函数),因此这个推导路径是完全可行的。
Clang的错误在于,它仅考虑了用户定义构造函数b(T)对应的推导指南(推导出b<d>,但该构造函数因约束不可行),却遗漏了拷贝构造函数对应的推导路径,导致错误判定代码非法。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

