使用C++ concepts定义任意嵌套initializer_list构造函数报错问题
问题原因
- Concept约束参数顺序错误:你定义的
maybe_nested_initializer_list_of第一个参数是元素类型T,第二个是待检查类型U,但使用template <maybe_nested_initializer_list_of<T> U>的简写语法时,C++20会默认将被约束的类型U作为concept的第一个参数,你传入的T作为第二个参数,相当于实际检查的是maybe_nested_initializer_list_of<U, T>,和你需要的约束逻辑完全相反,导致二维初始化时构造函数的约束不满足,不参与重载决议。 - 列表初始化的参数解析规则:当你使用
NDArray<int> two{{1,2},{3,4}}的花括号初始化语法时,编译器会将顶层的两个花括号初始化列表{1,2}和{3,4}识别为两个独立的构造函数参数,而你的构造函数只接受一个参数,自然匹配失败。一维初始化one{1,2}时,两个int正好匹配std::initializer_list<int>的元素定义,所以可以正常匹配。
解决方案
方案1:改用显式requires约束,避免参数顺序错误
直接在构造函数模板上用requires子句显式声明约束,无需修改原有类型萃取和concept定义:
template <typename T> class NDArray { std::vector<std::size_t> shape; std::vector<T> vector; public: template <typename U> requires maybe_nested_initializer_list_of<T, U> constexpr NDArray(std::initializer_list<U> il) { // 原有实现逻辑 } };
初始化时选择以下任意一种写法即可正常编译:
int main() { NDArray<int> one{1, 2}; // 一维初始化不受影响 // 写法1:用圆括号包裹初始化列表,避免参数被拆分 NDArray<int> two({{1,2},{3,4}}); // 写法2:多套一层花括号,让顶层只有一个参数 NDArray<int> two{{{1,2},{3,4}}}; }
方案2:调整Concept参数顺序适配简写语法
如果你想保留template <maybe_nested_initializer_list_of<T> U>的简写写法,可以将concept的参数顺序反转定义:
// 调整参数顺序:第一个为待检查类型U,第二个为元素类型T template <typename U, typename T> concept maybe_nested_initializer_list_of = std::is_same_v<T, U> || nested_initializer_list_of<T, U>;
类定义和初始化写法和方案1完全一致。
内容的提问来源于stack exchange,提问作者QuaternionsRock
相关产品推荐
相关产品推荐

