gcc 允许使用另一个数组引用初始化 const 数组成员是错误的吗?

Mat*_*atG 7 c++ arrays member-initialization c++20 consteval

在(重新)实现一个简单的 constexpr 映射时,我写了这个(godbolt):

template <class key_type, class value_type, int N>
class flat_map
{
private:
    struct pair
    {
        key_type key;
        value_type value;
    };
    const pair elements[N];

public:
    consteval flat_map(const pair (&arr)[N]) noexcept
        : elements(arr) // works on gcc?!
    {}

    [[nodiscard]] consteval value_type operator[](const key_type key) const
    {
        for (const pair &elem : elements)
            if (elem.key == key)
                return elem.value;
        throw "Key not found";
    }
};

constexpr flat_map<int, char, 3> m = {{
    { 4, 'a' }, { -1, 'b' }, { 42, 'c' }
}};
static_assert(m[4] == 'a');
static_assert(m[-1] == 'b');
static_assert(m[42] == 'c');

int main()
{
    return m[4]; // 97=='a'
}
Run Code Online (Sandbox Code Playgroud)

我天真地认为将私有数组设置elementsconst并在构造函数中初始化它;我使用gcc trunk 作为编译器,一切似乎都运行良好。当我决定使用msvcclang尝试它时,我遇到了编译错误:两者都在抱怨数组初始化需要大括号括起来的初始值设定项列表。

事后看来,其他编译器并没有特别错误,不是吗?我是否无意中使用了一些gcc非标准扩展?

嗯,顺便问一下,您会如何避免手动复制数组元素?

use*_*170 8

[class.base.init]/7 :

\n
\n

mem-initializer中的表达式列表花括号初始化列表用于根据 [dcl.init] 的初始化规则初始化指定的子对象(或者,在委托构造函数的情况下,初始化完整的类对象)直接初始化。

\n
\n

[dcl.init.general]/16.5

\n
\n

否则,如果目标类型是数组,则对象将按如下方式初始化。令x 1 , \xe2\x80\xa6, x k为表达式列表的元素。如果目标类型是未知边界的数组,则它被定义为具有k 个元素。令n表示此潜在调整后的数组大小。如果k大于n,则程序格式错误。否则,对于每个 1 \xe2\x89\xa4 i \xe2\x89\xa4 k ,第i个数组元素使用x i进行复制初始化,并且对于每个k < i \xe2\x89\xa4 n进行值初始化。对于每个 1 \xe2\x89\xa4 i < j \xe2\x89\xa4 n ,与数组的第 i个元素的初始化相关的每个值计算和副作用都在与第 j元素的初始化相关的计算和副作用之前排序元素。

\n
\n

第 16.5 点优先于随后的所有点,特别是那些涵盖相同类型值的复制初始化的点(16.6 和 16.9)。因此,只能通过单独初始化 array\xe2\x80\x99s 中的每个元素来初始化数组数据成员。因此,GCC\xe2\x80\x99s 的行为是不合格的。

\n


max*_*x66 7

我是否无意中使用了一些 gcc 非标准扩展?

是的...我想 gcc 使用的是非标准扩展

嗯,顺便问一下,您会如何避免手动复制数组元素?

为什么要避免它?使用委托构造函数很简单。

您可以用以下内容替换您的构造函数

template <std::size_t ... Is>
consteval flat_map(const pair (&arr)[N],
                   std::index_sequence<Is...> const &) noexcept
  : elements{ arr[Is]... }
   {}

consteval flat_map(const pair (&arr)[N]) noexcept
  : flat_map(arr, std::make_index_sequence<N>{})
   {}
Run Code Online (Sandbox Code Playgroud)