C++20标准下该代码是否合法?Clang接受GCC/MSVC拒绝
C++20标准下这段代码是否合法?
我原本认为,由于存在用户定义的转换运算符constexpr operator bool() const,x可以被用作bool类型的转换常量表达式。但GCC和MSVC拒绝这段代码,而Clang却能接受。请问根据C++20标准,这段代码是否合法?
代码示例
template<bool B> struct s { constexpr operator bool() const { return B; } }; constexpr auto f(auto x) -> s<x> { return {}; } static_assert(f(s<true>{})); // clang ok, gcc nope, msvc nope
编译器错误信息
GCC错误信息
<source>:3:32: 错误:模板实参1无效 3 | constexpr auto f(auto x) -> s<x> { return {}; } | ^ <source>:3:32: 错误:模板实参1无效 <source>:3:32: 错误:模板实参1无效 <source>:3:32: 错误:模板实参1无效 <source>:3:29: 错误:无效的模板ID 3 | constexpr auto f(auto x) -> s<x> { return {}; } | ^ <source>:3:32: 错误:在'>'标记前在函数体外使用参数 3 | constexpr auto f(auto x) -> s<x> { return {}; } | ^ <source>:3:11: 错误:函数返回类型中推导的类类型's' 3 | constexpr auto f(auto x) -> s<x> { return {}; } | ^~~~ <source>:2:8: 注:'template<bool B> struct s'在此声明 2 | struct s { constexpr operator bool() const { return B; } }; | ^ <source>:4:15: 错误:'f'未在此作用域中声明 4 | static_assert(f(s<true>{})); | ^
MSVC错误信息
<source>(4): error C2440: 'static_assert': 无法从's<x>'转换为'bool' <source>(4): note: 没有可用的用户定义转换运算符可以执行此转换,或者无法调用该运算符
结论分析
根据C++20标准,这段代码不合法,Clang的接受属于编译器扩展或实现偏差。
核心问题出在函数f的返回类型s<x>上:
- 非类型模板实参要求是转换后的常量表达式,但模板实参的转换只允许标准转换序列,不包含用户定义的转换。这里的
x是函数参数,即使它带有constexpr operator bool(),也无法通过用户定义转换将其转换为bool类型作为模板实参。 - 函数参数
x在模板实参位置时,无法在编译期确定其值——模板实参必须在模板实例化阶段就完全确定,而函数参数的用户定义转换不属于该阶段允许的常量计算范畴,导致s<x>的模板实例化直接失败。 - 后续
static_assert的错误本质是f因返回类型解析失败未被正确声明,或返回的s类型未完成有效实例化,自然无法触发operator bool()转换。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

