C++ C+中的默认构造函数、POD初始化和隐式类型转换+;11

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); } #包

我刚刚看了钱德勒在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);
}
#包括
结构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的解析,这两种情况都将无效。