可变模板编译失败,是否属于Clang编译器Bug?
Clang编译C++23代码报错,是否属于编译器Bug?
我把代码简化成以下示例:
template<class ...F> struct A { A(std::convertible_to<std::tuple<std::string, F>> auto&&... actions); std::tuple<std::tuple<std::string, F>...> _actions; }; template<class ...F> A<F...>::A(std::convertible_to<std::tuple<std::string, F>> auto&&... actions) : _actions{ std::tuple{ actions... } }{}
用Clang(-std=c++23)编译时出现如下错误:
<source>:13:66: error: pack expansion contains parameter packs 'actions:auto' and 'F' that have different lengths (1 vs. 0) 13 | A<F...>::A(std::convertible_to<std::tuple<std::string, F>> auto&&... actions) | ~ ^ ~~~~~~~ <source>:13:10: note: while calculating associated constraint of template '' here 13 | A<F...>::A(std::convertible_to<std::tuple<std::string, F>> auto&&... actions) | ^ <source>:13:10: error: out-of-line definition of 'A<F...>' does not match any declaration in 'A<F...>' 13 | A<F...>::A(std::convertible_to<std::tuple<std::string, F>> auto&&... actions) | ^ 2 errors generated.
请问该编译失败是否属于Clang编译器Bug?
这不是Clang的Bug,而是代码写法不符合C++标准的要求。
问题出在类模板构造函数的声明与定义的匹配上:类内声明的构造函数中,std::convertible_to<std::tuple<std::string, F>> auto&&... actions是一个包扩展约束——要求每个actions参数分别对应F包中的一个类型,即actions的参数数量必须和F的模板参数数量完全一致。但在类外定义时,Clang无法正确解析这个包扩展的对应关系,导致认为两个参数包长度不匹配,进而判定定义与声明签名不匹配。
要修复这个问题,需要调整构造函数的写法,让约束的包扩展关系更清晰。比如将构造函数改为显式的模板构造函数,明确约束每个参数与F包中对应类型的转换关系:
template<class ...F> struct A { template<class... Args> requires (std::convertible_to<Args, std::tuple<std::string, F>> && ...) A(Args&&... actions); std::tuple<std::tuple<std::string, F>...> _actions; }; template<class ...F> template<class... Args> requires (std::convertible_to<Args, std::tuple<std::string, F>> && ...) A<F...>::A(Args&&... actions) : _actions{ std::forward<Args>(actions)... }{}
或者,如果希望保留auto参数的写法,可以改用折叠表达式约束,确保每个参数都能转换为对应F类型的tuple:
template<class ...F> struct A { A(auto&&... actions) requires (std::convertible_to<decltype(actions), std::tuple<std::string, F>> && ...); std::tuple<std::tuple<std::string, F>...> _actions; }; template<class ...F> A<F...>::A(auto&&... actions) requires (std::convertible_to<decltype(actions), std::tuple<std::string, F>> && ...) : _actions{ std::forward<decltype(actions)>(actions)... }{}
这两种写法都能让Clang正确识别约束与参数包的对应关系,顺利通过编译。
内容的提问来源于stack exchange,提问作者Gene
相关产品推荐
相关产品推荐

