C++ 在C+中初始化结构+;
作为附录,这里发生了什么:C++ 在C+中初始化结构+;,c++,struct,C++,Struct,作为附录,这里发生了什么: #include <string> using namespace std; struct A { string s; }; int main() { A a = {0}; } 这两种定义是否明确 这又是一个让我尴尬的问题——我总是给我的结构构造函数,所以这个问题以前从未出现过。您的结构是一个聚合,因此聚合初始化的普通规则适用于它。该过程如8.5.1所述。基本上整个8.5.1都致力于此,所以我不认为有理由在这里复制整个内容。其基本思想
#include <string>
using namespace std;
struct A {
string s;
};
int main() {
A a = {0};
}
这两种定义是否明确
这又是一个让我尴尬的问题——我总是给我的结构构造函数,所以这个问题以前从未出现过。您的结构是一个聚合,因此聚合初始化的普通规则适用于它。该过程如8.5.1所述。基本上整个8.5.1都致力于此,所以我不认为有理由在这里复制整个内容。其基本思想与C中的基本思想相同,只是适应了C++:从右边取一个初始值设定项,从左边取一个成员,然后用该初始值设定项初始化该成员。根据8.5/12,这应是一个副本初始化
当你这样做的时候
A a = { 0 };
您基本上是使用0
复制初始化a.s
,即对于a.s
,它在语义上等同于
string s = 0;
上述编译是因为std::string
可从const char*
指针转换而来。(这是未定义的行为,因为在这种情况下,null指针不是有效的参数。)
您的42
版本将无法编译,原因与
string s = 42;
不会编译42
不是空指针常量,std::string
无法从int
类型转换
<强> P.S.以防万一:注意C++中的聚合定义不是递归的(与POD的定义相反)。code>std::string不是聚合,但它不会更改
A
的任何内容<代码>A仍然是一个聚合。8.5.1/12“聚合”表示:
当使用初始值设定项列表中的初始值设定项初始化聚合成员时,将考虑所有隐式类型转换(第4条)
所以
将使用NULLchar*
进行初始化(如图所示),并且
将在编译时失败,因为没有与
std::string
构造函数匹配的隐式转换。正如人们所指出的,这个“工作”是因为string有一个可以将0作为参数的构造函数。如果我们说:
#include <map>
using namespace std;
struct A {
map <int,int> m;
};
int main() {
A a = {0};
}
#包括
使用名称空间std;
结构A{
地图m;
};
int main(){
A={0};
}
然后我们得到一个编译错误,因为map类没有这样的构造函数。在21.3.1/9中,标准禁止
std::basic_字符串的相关构造函数的char*
参数作为空指针。这应该会抛出一个std::logic_错误
,但我还没有看到标准中的哪一个保证违反前提条件会抛出std::logic_错误0是一个空指针常量
S.4.9:
空指针常量是整数类型的整数常量表达式(5.19)右值,其计算结果为
零
空指针常量可以转换为任何其他指针类型:
S.4.9:
空指针常量可以转换为指针类型;结果是该值的空指针值
类型
您为A
定义提供的内容被视为一个集合:
S.8.5.1:
聚合是一个数组或类,没有用户声明的构造函数,没有私有或受保护的构造函数
非静态数据成员,没有基类,也没有虚拟函数
您正在指定初始值设定项子句:
S.8.5.1:
初始化聚合时,初始值设定项可以包含包含括号的初始值设定项子句,
聚合成员的初始值设定项子句的逗号分隔列表
A
包含类型为std::string
的聚合的成员,并且初始值设定项子句适用于该聚合。
您的聚合已被复制初始化
当聚合(无论是类还是数组)包含类类型的成员并由括号初始化时
初始化器列表中,每个这样的成员都是副本初始化的
复制初始化意味着您拥有与std::string s=0
或std::string s=42
等效的文件强>
S.8.5-12
在参数传递、函数返回、引发异常(15.1)、处理
例外情况(15.3)和括号内的初始值设定项列表(8.5.1)称为复制初始化,与之等效
形式为T x=a
std::string s=42
不会编译,因为没有隐式转换,std::string s=0
会编译(因为存在隐式转换),但会导致未定义的行为。
std::string
的const char*
的构造函数未定义为显式,这意味着您可以这样做:std::string s=0
为了显示实际正在进行复制初始化,您可以执行以下简单测试:
class mystring
{
public:
explicit mystring(const char* p){}
};
struct A {
mystring s;
};
int main()
{
//Won't compile because no implicit conversion exists from const char*
//But simply take off explicit above and everything compiles fine.
A a = {0};
return 0;
}
类模板也是一个聚合。所以你可以做数组a={“foo”,“bar”}例如,代码>使用它。另外,我的惰性构造数组也是一个聚合:隐式转换+聚合。。。ಠ_ಠ@litb当我第一次看到boost::array的特性时,我有了一个启示,也就是大脑的性满足感。非常有意义的简单事情往往会对我产生影响。§12.6.1也是相关的,如§8.5.1 13中所述。@outis:我查看了12.6.1,但无法立即看到它在8.5中已经添加了什么。每次12.6.1处理聚合初始化时,似乎都要回到8.5:)有趣的是,在basic\u字符串(size\u type n,charT c,const Allocator a=Allocator())中,
有一个原因,为什么size\u type n
没有默认值。原因是在指针和整数上重载是个坏主意。值0(零)为stric
A a = {42};
#include <map>
using namespace std;
struct A {
map <int,int> m;
};
int main() {
A a = {0};
}
class mystring
{
public:
explicit mystring(const char* p){}
};
struct A {
mystring s;
};
int main()
{
//Won't compile because no implicit conversion exists from const char*
//But simply take off explicit above and everything compiles fine.
A a = {0};
return 0;
}