C++:初始化 constexpr 构造函数中的成员数组



我正在用 c++17 实现一个类,该类需要能够在编译时使用constexpr构造函数构造对象。该对象有一个数组成员,我似乎无法通过参数初始化。

我一直在尝试为此使用std::initializer_list,大致如下:

#include <cstdint>
#include <initializer_list>
struct A {
char data[100];
constexpr A(std::initializer_list<char> s): data(s) {}
};
int main() {
constexpr A a{"abc"};
}

但由于某种原因,这不起作用。

clang 6.0(也尝试了后来的版本(告诉我我错了,尽管我正在按照它所说的去做:

test_initializer_list.cpp:7:46: error: array initializer must be an initializer list or string literal
constexpr A(std::initializer_list<char> s): data(s) {}

(请注意,如果我直接给它一个字符串文字,比如data("abc"),它确实可以编译(

g++(7.5.0( 说由于某种原因我无法使用初始值设定项列表 - 但如果是这样,我可以使用什么?

test_initializer_list.cpp:7:52: error: incompatible types in assignment of 'std::initializer_list<char>' to 'char [100]'
constexpr A(std::initializer_list<char> s): data(s) {}
^

我做错了什么吗?

解释会很长,但请耐心等待。


不能使用std::initializer_list初始化数组。

当你写类似int arr[] = {1,2,3}的东西时,用大括号括起来的部分不是std::initializer_list

如果您不相信我,请考虑对结构进行类似的初始化:

struct A {int x; const char *y;};
A a = {1, "2"};

在这里,{1, "2"}不可能是std::initializer_list,因为元素有不同的类型。

C++语法将这些大括号括起来的列表称为大括号初始化列表s。

std::initializer_list是一个神奇的类(也就是说,在标准C++中无法实现(,可以从大括号的初始化列表构造

正如您所注意到的,std::initializer_list不能代替大括号的初始化列表。"大括号-init-list"是指特定的语法结构,因此数组的初始值设定项(例如在成员 init 列表中(必须是一个大括号括起来的列表。不能将此列表保存到变量中,并在以后使用它初始化数组。

constexpr A() : data{'1','2','3'} {} // Valid
constexpr A(initializer_list<char>/*or whatever*/ list) : data{list} {} // Not possible

一种可能的解决方案是使用循环将元素从std::initializer_list复制到数组中。

由于构造函数是constexpr的,数组必须用某些东西初始化;用零初始化它,使用: data{}

constexpr A(std::initializer_list<char> s) : data{} {/*copy elements here*/}

现在A a({'1','2','3'});将起作用。但A a("123");仍然不会。

字符串文字("123"(既不是大括号的初始化列表,也不是std::initializer_list,并且不能转换为它们。

有一个特殊的规则用于初始化char数组与字符串文字 (char x[] = "123";(。除了大括号的初始化列表之外,语法还允许在此处使用字符串文本。

它必须是字符串文字,即用引号括起来的字符串;const char *变量或其他char数组不行。

如果您希望A a("123");有效,构造函数的参数需要是一个const char *(还有一些其他选项,但它们在这里没有多大帮助(。使用循环将字符从指向内存复制到数组中。不要忘记用零(: data{}(初始化数组,因为你的构造函数是constexpr的。

还有第三种选择:将char data[100]替换为std::array,并使构造函数的参数成为std::array。与普通数组不同,这些数组可以复制,因此: data(list)工作。std::array可以用大括号初始化列表(A a({'1','2','3'});(和大括号括起来的字符串文字(A a({"123"});(进行初始化。

您还有另一种选择:删除构造函数。然后,您的struct将成为聚合(简单地说,一个没有自定义构造函数的结构,可以使用大括号的 init-list 按成员初始化(。然后两个A a{{'1','2','3'}};A a{'1','2','3'};(可以省略大括号(和A a{"123"};都可以。

最新更新