为什么我在使用花括号初始化结构体时会出现错误?

4
我正在使用以下代码并且出现错误。我不明白为什么会出现这个错误。
prog.cpp: In function ‘int main()’:
prog.cpp:15:44: error: could not convert ‘{"foo", true}’ from 
                       ‘<brace-enclosed initializer list>’ to ‘option’
                       option x[] = {{"foo", true},{"bar", false}};
                                            ^
prog.cpp:15:44: error: could not convert ‘{"bar", false}’ from 
                       ‘<brace-enclosed initializer list>’ o ‘option’

这段代码

#include <iostream>
#include <string>
 
struct option
{
    option();
    ~option();
 
    std::string s;
    bool b;
};
 
option::option() = default;
option::~option() = default;

int main()
{
    option x[] = {{"foo", true},{"bar", false}};
}

只需移除默认构造函数和析构函数,或者添加一个带有两个参数的构造函数。 - Ted Lyngmo
1
你正在编译哪个版本的C++?每个版本聚合规则都有所改变,因此这很重要。 - NathanOliver
在我看来,如果没有提供两个参数的构造函数,花括号会降低option类的封装性。为什么用户必须知道可以这样设置两个成员变量呢?我可以理解像vector<int>这样的东西,你知道要使用int来填充对象,但是option呢?提供适当的构造函数,使得option由两个值组成显而易见,并且object的构造函数可以找出如何设置这些值。 - PaulMcKenzie
1个回答

6
当你提供默认构造函数和析构函数时,你让结构体成为了一个非聚合类型,因此无法进行聚合初始化。
但是,你可以使用标准的std::is_aggregate_v特性来检查一个类型是否是聚合类型(自c++17起)。
看看你的情况。它不是一个聚合体,因为你提供了这些构造函数。
你有以下三种方法使其工作:

以下文章解释了构造函数什么时候会被默认,何时被视为用户声明用户提供:(致谢 @NathanOliver)

C++零初始化-为什么这个程序中的`b`未初始化,而`a`已初始化?


有没有其他方法可以不删除默认构造函数。 - Ashutosh Kumar Ray
1
@AshutoshKumarRay 您可以添加一个接受两个参数的构造函数。 - Ted Lyngmo
这比你的回答看起来更微妙一些。例如,这个可以编译通过:http://coliru.stacked-crooked.com/a/856bbadf418fe86a - NathanOliver
2
@JeJo 但是这个有,而且它有成员明确的默认值:https://godbolt.org/z/o6q-Z7 - NathanOliver
5
在类内声明构造函数为默认构造函数时,它被视为用户声明的构造函数。在类外将其设为默认,则是用户提供的构造函数。根据 C++ 的版本,这将影响它是否为聚合类型。请参见:https://dev59.com/rVQJ5IYBdhLWcg3wNi8h#54350350 - NathanOliver

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接