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

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

我正在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) {}
                                                    ^

我做错什么了吗?

c++ constexpr initializer-list
1个回答
2
投票

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


您无法使用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 ++语法将那些用大括号括起来的列表称为braced-init-lists

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

您已经注意到,std::initializer_list不能代替大括号初始列表。 “括号初始化列表”是指特定的语法构造,因此数组的初始化程序(例如,在成员初始化列表中)必须在字面上用括号括起来的列表。您无法将此列表保存为变量,以后再使用它初始化数组。constexpr A() : data{'1','2','3'} {} // Valid constexpr A(initializer_list<char>/*or whatever*/ list) : data{list} {} // Not possible

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

由于构造函数为constexpr,因此必须使用

something

初始化数组;使用: 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";数组。除了支撑初始列表外,该语法还允许在其中使用字符串文字。

必须是字符串

literal

,即用引号引起来的字符串;一个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将成为

aggregate

(简单地说,没有自定义构造函数的结构,可以使用braced-init-list进行成员初始化)。然后A a{{'1','2','3'}};A a{'1','2','3'};(大括号都可以省略)和A a{"123"};都可以使用。
© www.soinside.com 2019 - 2024. All rights reserved.