constexpr构造函数初始化数组是否合法?代码兼容性技术问询
在constexpr构造函数中初始化数组是否符合C++标准?
首先直接给结论:这段代码在C++20及之后的标准中是完全合法的,但在C++17及更早版本中不符合标准——这也是不同编译器表现不一致的核心原因。
为什么不同编译器结果不同?
你给出的代码:
template <int N> class foo { public: constexpr foo() { for (int i = 0; i < N; ++i) { v_[i] = i; } } private: int v_[N]; }; constexpr foo<5> bar;
- Clang编译通过:因为它默认或显式启用了C20标准,而C20大幅放宽了constexpr函数的限制,允许在constexpr构造函数的函数体中对未初始化的非静态成员进行赋值,只要整个操作符合常量表达式的要求。
- GCC和MSVC报错:这两个编译器在当前启用的标准下(比如默认的C++17),遵循旧规则:constexpr构造函数要求所有非静态数据成员必须在成员初始化列表中完成初始化,不能在函数体里对未初始化的成员赋值。GCC的报错信息也明确指出了这一点:
member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor。
标准的变化点
在C20之前,constexpr构造函数的函数体只能包含非常有限的操作,比如初始化列表、对已初始化成员的简单赋值、少量控制流等。而C20解除了这些限制,允许在constexpr函数中使用循环、对未初始化的成员赋值,甚至使用部分STL容器(只要操作符合常量表达式要求)。
关于减少index_sequence的使用
没错,如果这段代码能在C++20下合法使用,确实可以大幅减少std::index_sequence的使用场景。之前很多需要用index_sequence来编译期展开初始化数组的场景,现在用一个简单的for循环就能实现,代码的可读性和简洁性都会提升很多。
兼容旧标准的写法(如果需要)
如果你的项目需要兼容C++17及更早版本,可以用std::index_sequence配合成员初始化列表来实现相同效果:
#include <utility> template <int N> class foo { public: constexpr foo() : foo(std::make_integer_sequence<int, N>{}) {} private: template <int... Is> constexpr foo(std::integer_sequence<int, Is...>) : v_{Is...} {} int v_[N]; }; constexpr foo<5> bar;
内容的提问来源于stack exchange,提问作者Yongwei Wu
相关产品推荐
相关产品推荐

