在 constexpr 构造函数中初始化数组是否合法?
Legitimate to initialize an array in a constexpr constructor?
以下代码合法吗?
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接受它,但GCC和MSVC拒绝它。
GCC 的错误是:
main.cpp:15:18: error: 'constexpr foo<N>::foo() [with int N = 5]' called in a constant expression
15 | constexpr foo<5> bar;
| ^~~
main.cpp:4:15: note: 'constexpr foo<N>::foo() [with int N = 5]' is not usable as a 'constexpr' function because:
4 | constexpr foo()
| ^~~
main.cpp:4:15: error: member 'foo<5>::v_' must be initialized by mem-initializer in 'constexpr' constructor
main.cpp:12:9: note: declared here
12 | int v_[N];
| ^~
如果这种代码没问题,我可以减少很多index_sequence
的使用。
在constexpr
上下文中禁止简单的默认初始化,直到C++20。
我猜,原因是很容易"意外"地从默认初始化的原语中读取,这种行为会给你的程序提供未定义的行为,并且具有未定义行为的表达式被直接禁止constexpr
(ref(。该语言已经扩展,因此现在编译器必须检查是否发生了这样的读取,如果没有,则应接受默认初始化。对于编译器来说,这需要做更多的工作,但是(如您所见!(对程序员有实质性的好处。
本文建议允许在 constexpr 上下文中对普通的默认可构造类型进行默认初始化,同时继续禁止调用未定义的行为。简而言之,只要未初始化的值不被读取,在堆和堆栈分配的场景中,constexpr 中都应该允许这种状态。
从 C++20 开始,像您一样v_
"未初始化"是合法的。然后你继续为其所有元素分配值,这很棒。
虽然这不能直接回答你的问题,但我认为至少值得一提。您可以简单地使用类内初始化并将数组零初始化:
int v_[N]{};
另一种方法,无需先初始化数组,是(私下(从std::array
继承。奇怪的是,这实际上被GCC接受,但没有被Clang接受:
#include <array>
template<int N>
struct foo : private std::array<int, N> {
constexpr foo() {
for (auto i = int{}; i < N; ++i) {
(*this)[i] = i;
}
}
};
constexpr foo<5> bar;
相关文章:
- 如何找到大小'x'数组是否完全填充,在C++?
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- 是否基于数组B整数打印数组A中的整数
- 检查TCHAR数组输入是否为带符号整数C++
- 堆栈和队列是否像C++中的数组一样传递?
- 在函数范围内在堆栈上分配的数组在离开函数时是否总是被释放?
- 是否假定reinterpret_cast<char*>(myTypePtr)指向数组?
- 如果分配数组引发异常,是否应该释放该数组
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 我是否不正确地集中了这些字符数组?
- 是否可以就地构造一个固定大小的数组作为函数参数?
- 在 c++ 中是否允许创建具有运行时边界的数组?
- C++ 返回指向函数内定义的静态数组的指针是否有效?
- 检查输入 std::array 指针数据是否等于某个常量数组
- 给定一个大小为 N 的数组 S,检查是否可以将序列拆分为两个序列
- C++:在多个线程中访问同一数组/向量的不同单元格是否会产生数据竞赛?
- 将对象的字节复制到数组并再次复制回来是否安全
- 是否可以将结构数组别名为结构成员数组?
- 当另一个数组是内存集时,内存集是否会更改数组长度?
- 任意大小的 constexpr 数组是否可以用作 switch 语句中的案例?