是否可以在constexpr构造函数中初始化数组?

问题描述 投票:0回答:1

以下代码是否合法?

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的很多使用。

c++ template-meta-programming constexpr compile-time-constant
1个回答
4
投票

constexpr上下文until C++20中禁止进行默认默认初始化。

我猜,原因是很容易“意外地”从默认初始化的原语中读取,该行为使您的程序具有未定义的行为,并且带有未定义行为的表达式被禁止直接被constexpr禁止(ref)。不过,该语言已经扩展,因此现在编译器必须检查是否发生了这种读取,如果没有发生,则应接受默认初始化。对于编译器来说,这需要更多的工作,但是(如您所见!)对程序员而言具有实质性的好处。

本文提出在constexpr上下文中允许对普通的默认可构造类型的默认初始化,同时继续禁止调用未定义的行为。简而言之,只要不读取未初始化的值,在堆分配和堆栈分配的方案中constexpr中都应允许这种状态。

自C ++ 20起,像您一样将v_保留为“未初始化”是合法的。然后,您继续为其分配所有元素值,这很棒。

© www.soinside.com 2019 - 2024. All rights reserved.