C++ C+中的默认构造函数、POD初始化和隐式类型转换+;11
我刚刚看了钱德勒在2012年《走向本土》上关于叮当声的演讲。他给出了以下代码:C++ C+中的默认构造函数、POD初始化和隐式类型转换+;11,c++,c++11,C++,C++11,我刚刚看了钱德勒在2012年《走向本土》上关于叮当声的演讲。他给出了以下代码: #include <iostream> struct S{ int n; }; struct X{ X(int) {}; }; void f( void* ) { std::cerr << "Pointer!\n"; } void f( X ) { std::cerr << "X!\n"; } int main() { f(S().n); } #包
#include <iostream>
struct S{ int n; };
struct X{ X(int) {}; };
void f( void* )
{
std::cerr << "Pointer!\n";
}
void f( X )
{
std::cerr << "X!\n";
}
int main()
{
f(S().n);
}
#包括
结构S{int n;};
结构X{X(int){};};
无效f(无效*)
{
首先,对C++03和C++11的初始化规则进行一些澄清:
// This is default construction
S s;
// s.i has undefined value
// This is initialization from a value-initialized S (C++03 rules)
S s = S();
// s.i has been zero-initialized
// This is value initialization (C++11 rules)
// new syntax, better rules, same result
S s {};
// s.i has been zero-initialized
然后,请记住int
不能转换为void*
,因此在C++03中f(S().n)
永远不会调用void f(void*);
即使没有其他f
的声明可用
在C++03中可以做的是f(0)
,它将调用void f(void*);
,即使存在void f(X);
。原因是int
->X
转换(所谓的用户定义转换)并不比零积分常数->void*
转换更可取(这不是UD转换)。请注意,也可以通过f((int())
调用void f(void*);
,因为int()
也是一个零整数常量,即使在C++03中也是如此。(通常这里的括号用于解决语法歧义。)
C++11改变的是现在的S().n
是一个零整数常量。原因是S()
现在是一个常量表达式(得益于广义常量表达式),并且这种成员访问也被禁用
首先,假设成员的零初始化是正确的吗
变量n依赖于编译器实现,不受
标准(或者c++11是否改变了这一点)
不,S()
在C++03和C++11中都表示值初始化。尽管我认为C++11中的措辞比C++03清楚得多。在这种情况下,值初始化将转发到零初始化。与不为零的默认初始化相比:
S s1; // default initialization
std::cout << s1.n << '\n'; // prints garbage, crank up optimizer to show
S s2 = S(); // value initialization
std::cout << s2.n << '\n'; // prints 0
s1;//默认初始化
std::你能知道是否有关于这个的缺陷报告吗?我没有看到任何缺陷报告,但我可能错过了它。谢谢,我从来不会写这样的代码,只是在看了Chandler的演示后感兴趣……啊,NVM,我现在明白了“一个int”的意思是“一个int变量”。我很困惑,以为你的意思是说“0”不是int或int表达式永远不能是null指针常量。CWG 903是相关的,但我不认为是这样。我个人没有参与这个问题,只是在窃听它(然后只听了半个耳朵)。我敢打赌约翰内斯·舒阿布(Johannes Schuab)可以用比我更精确的语言描述这种情况。现在应该有一个新的CWG问题列表,可能会有一个新的问题。我个人也没有参与。但是,理查德最近提出了类似的案例,例如“f(g());”当g被定义为“constexpr int g(){return 0;}”。“g()”和“S().n”的情况非常相似,因为这两种情况都是由C++11引入的,并且都不可取。在任何情况下,通过CWG903的解析,这两种情况都将无效。