C++11 为什么C++;11不支持指定的初始值设定项列表为C99?
考虑:C++11 为什么C++;11不支持指定的初始值设定项列表为C99?,c++11,c++,c,initialization,c99,c++20,c++17,C++11,C++,C,Initialization,C99,C++20,C++17,考虑: struct Person { int height; int weight; int age; }; int main() { Person p { .age = 18 }; } 上述代码在C99中是合法的,但在C++11中不合法 标准委员会排除对这种便捷功能的支持的理由是什么?C++有构造函数。如果只初始化一个成员是有意义的,那么可以通过实现适当的构造函数在程序中表示。这是C++的一种抽象提法。 另一方面,指定初始值设定项功能更多的是在客户端代码中
struct Person
{
int height;
int weight;
int age;
};
int main()
{
Person p { .age = 18 };
}
上述代码在C99中是合法的,但在C++11中不合法
标准委员会排除对这种便捷功能的支持的理由是什么?C++有构造函数。如果只初始化一个成员是有意义的,那么可以通过实现适当的构造函数在程序中表示。这是C++的一种抽象提法。 另一方面,指定初始值设定项功能更多的是在客户端代码中公开并使成员易于直接访问。这导致了一些事情,比如有一个18岁但身高和体重为零的人
换句话说,指定的初始值设定项支持一种编程风格,在这种风格中,内部内容是公开的,并且客户机可以灵活地决定如何使用该类型 C++更感兴趣的是将灵活性放在类型的设计器上,这样,设计器就可以轻松地正确使用类型,而不容易错误地使用类型。让设计器控制如何初始化类型是其中的一部分:设计器确定构造函数、类内初始值设定项等。2017年7月15日被接受为标准:
这给公司指定的初始值设定者带来了有限的支持。C.1.7[diff.decl].4对该限制进行了如下描述,给出:
struct A { int x, y; };
struct B { struct A a; };
以下在C中有效的指定初始化在C++中受到限制:
-
<代码>结构A = { y=1,x=2 } <代码>在C++中无效,因为指定符必须出现在数据成员< /LI>的声明顺序中
<>代码> int ARR(3)={[1 ]=5 } <代码>在C++中无效,因为数组指定初始化不支持
<>代码>结构B b= { .x=0 } <代码>在C++中无效,因为指定符不能嵌套
对于和更早的Boost,事实上已经有了,并且已经有很多建议来增加对该标准的支持,例如:和。建议引用Visual C++、GCC和CLAN中的指定初始化器的实现: 我们相信,这些变化将相对容易实施 但标准委员会一再声明: EWG发现了提议方法的各种问题,并且认为尝试解决问题是不可行的,因为它已经尝试了很多次,每次都失败了 帮助我看到了这种方法无法克服的问题;鉴于:
struct X {
int c;
char a;
float b;
};
这些函数的调用顺序是:struct X foo={.a=(char)f(),.b=g(),.c=h()}
?令人惊讶的是,在:
任何初始值设定项中的子表达式的求值顺序都是不确定的[]
(VisualC++)和Clang似乎有一致的行为,因为他们都会这样称呼:
h()
f()
g()
f()
g()
h()
如上所述,这一问题已被接受的指定初始值设定人的限制所回避。它们提供了标准化的行为,保证指定初始化器的执行顺序。 < P> C++ 11没有提到“指定Initializers和C++”。 我认为“指定初始值设定项”与潜在优化有关。这里我使用“gcc/g++”5.1作为示例
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct point {
int x;
int y;
};
const struct point a_point = {.x = 0, .y = 0};
int foo() {
if(a_point.x == 0){
printf("x == 0");
return 0;
}else{
printf("x == 1");
return 1;
}
}
int main(int argc, char *argv[])
{
return foo();
}
foo
优化为仅打印x==0
< C++版本>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
struct point {
point(int _x,int _y):x(_x),y(_y){}
int x;
int y;
};
const struct point a_point(0,0);
int foo() {
if(a_point.x == 0){
printf("x == 0");
return 0;
}else{
printf("x == 1");
return 1;
}
}
int main(int argc, char *argv[])
{
return foo();
}
#包括
#包括
#包括
结构点{
点(int x,int y):x(x),y(y){
int x;
int-y;
};
常数结构点a_点(0,0);
int foo(){
如果(a_点x==0){
printf(“x==0”);
返回0;
}否则{
printf(“x==1”);
返回1;
}
}
int main(int argc,char*argv[])
{
返回foo();
}
这是优化汇编代码的输出
g++ -O3 a.cc
$ gdb a.out
(gdb) disassemble foo
Dump of assembler code for function _Z3foov:
0x00000000004005c0 <+0>: push %rbx
0x00000000004005c1 <+1>: mov 0x200489(%rip),%ebx # 0x600a50 <_ZL7a_point>
0x00000000004005c7 <+7>: test %ebx,%ebx
0x00000000004005c9 <+9>: je 0x4005e0 <_Z3foov+32>
0x00000000004005cb <+11>: mov $0x1,%ebx
0x00000000004005d0 <+16>: mov $0x4006a3,%edi
0x00000000004005d5 <+21>: xor %eax,%eax
0x00000000004005d7 <+23>: callq 0x400460 <printf@plt>
0x00000000004005dc <+28>: mov %ebx,%eax
0x00000000004005de <+30>: pop %rbx
0x00000000004005df <+31>: retq
0x00000000004005e0 <+32>: mov $0x40069c,%edi
0x00000000004005e5 <+37>: xor %eax,%eax
0x00000000004005e7 <+39>: callq 0x400460 <printf@plt>
0x00000000004005ec <+44>: mov %ebx,%eax
0x00000000004005ee <+46>: pop %rbx
0x00000000004005ef <+47>: retq
g++-O3 a.cc
$gdb a.out
(gdb)分解foo
函数_Z3foov的汇编程序代码转储:
0x00000000004005c0:推送%rbx
0x00000000004005c1:mov 0x200489(%rip),%ebx#0x600a50
0x00000000004005c7:测试%ebx,%ebx
0x00000000004005c9:je 0x4005e0
0x00000000004005cb:mov$0x1,%ebx
0x00000000004005d0:mov$0x4006a3,%edi
0x00000000004005d5:xor%eax,%eax
0x00000000004005d7:callq 0x400460
0x00000000004005dc:mov%ebx,%eax
0x00000000004005de:弹出%rbx
0x00000000004005df:retq
0x00000000004005e0:mov$0x40069c,%edi
0x00000000004005e5:xor%eax,%eax
0x00000000004005e7:callq 0x400460
0x00000000004005ec:mov%ebx,%eax
0x00000000004005ee:弹出%rbx
0x00000000004005ef:retq
我们可以看到,
a_点
实际上并不是编译时常量值。指定的初始值设定项目前包含在C++20的工作中:
g++ -O3 a.cc
$ gdb a.out
(gdb) disassemble foo
Dump of assembler code for function _Z3foov:
0x00000000004005c0 <+0>: push %rbx
0x00000000004005c1 <+1>: mov 0x200489(%rip),%ebx # 0x600a50 <_ZL7a_point>
0x00000000004005c7 <+7>: test %ebx,%ebx
0x00000000004005c9 <+9>: je 0x4005e0 <_Z3foov+32>
0x00000000004005cb <+11>: mov $0x1,%ebx
0x00000000004005d0 <+16>: mov $0x4006a3,%edi
0x00000000004005d5 <+21>: xor %eax,%eax
0x00000000004005d7 <+23>: callq 0x400460 <printf@plt>
0x00000000004005dc <+28>: mov %ebx,%eax
0x00000000004005de <+30>: pop %rbx
0x00000000004005df <+31>: retq
0x00000000004005e0 <+32>: mov $0x40069c,%edi
0x00000000004005e5 <+37>: xor %eax,%eax
0x00000000004005e7 <+39>: callq 0x400460 <printf@plt>
0x00000000004005ec <+44>: mov %ebx,%eax
0x00000000004005ee <+46>: pop %rbx
0x00000000004005ef <+47>: retq
#define with(T, ...)\
([&]{ T ${}; __VA_ARGS__; return $; }())
MyFunction(with(Params,
$.Name = "Foo Bar",
$.Age = 18
));
MyFunction(([&] {
Params ${};
$.Name = "Foo Bar", $.Age = 18;
return $;
}()));