约束表达式中参数包展开是否无效?GCC与其他编译器编译差异咨询
约束表达式中参数包展开的有效性问题
以下代码可在Clang 15和MSVC 19.33中正常编译,但无法通过GCC 12.2或GCC主干版本的编译,疑问是该约束表达式中的参数包展开是否属于无效写法?
代码示例
struct s { constexpr auto b() const { return true; } }; template<typename... Ts> concept c = (requires(Ts ts) { ts.b(); // GCC编译报错 { ts.b() }; // GCC编译报错 requires Ts{}.b(); // GCC编译报错 Ts{}.b(); // 所有编译器都通过 { Ts{}.b() }; // 所有编译器都通过 } and ...); static_assert(c<s>);
GCC报错信息
<source>:7:14: error: operand of fold expression has no unexpanded parameter packs 7 | concept c = (requires(Ts ts) { | ^~~~~~~~~~~~~~~~~
解答
这种写法是符合C++标准的有效写法,GCC的报错属于编译器实现缺陷。
- 折叠表达式
(E and ...)中,E是requires(Ts ts) { ... },这里的Ts是模板参数包,折叠时会对包中的每个类型单独展开requires子句,参数包的展开完全合法。 - requires子句内的
ts.b()、{ ts.b() }、requires Ts{}.b()这几种写法,本质都是对参数包中每个类型的约束检查,和能通过编译的Ts{}.b()逻辑一致,区别仅在于前者使用requires参数获取对象实例,后者直接构造临时对象。 - GCC给出的“操作数无未展开参数包”提示是错误的,因为
Ts在requires子句中明确是待展开的参数包,完全符合C++20标准中折叠表达式的规则。
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

