Scott Meyers撰写的草案Effective C++11指出:
在创建对象时区分()和{}
Object obj(args...)
和Object obj{args...}
之间的区别是什么?为什么斯科特这么说。
更新
问题How to use C++11 uniform initialization syntax?如何询问,这个问题是为什么要求。
UPDATE2:
我发现以下链接很有帮助,完全回答了这个问题:
答案 0 :(得分:5)
Object obj(args...)
和Object obj{args...}
之间有什么区别?
第一个是直接初始化,第二个是 direct-list-initialization 。这在两个不同的部分提到:
§8.5/ 16 [dcl.init]
表单中出现的初始化
T x(a); T x{a};
以及
new
表达式(5.3.4),static_cast
表达式(5.2.9),功能表示法类型转换(5.2.3)以及基本和成员初始值设定项(12.6.2) )被称为 直接初始化 。
和§8.5.4/ 1 [dcl.init.list]
列表初始化是从 braced-init-list 初始化对象或引用。这样的初始化程序称为初始化列表,列表中逗号分隔的 initializer-clauses 称为初始化程序列表的元素。初始化列表可以为空。 列表初始化可以在直接初始化或复制初始化上下文中发生;直接初始化上下文中的列表初始化称为 direct-list-initialization ,复制初始化上下文中的列表初始化称为 copy-list-initialization
两者之间存在一些差异:
如果正在构造的类型具有带initializer_list
参数的构造函数, direct-list-initialization 将始终支持该构造函数。只有initializer_list
构造函数不可行时才会考虑其他构造函数。 §13.3.1.7/ 1 [over.match.list]
direct-list-initialization 不允许缩小参数列表中的转换范围。 §8.5.4/ 3 [dcl.init.list]
如果要初始化的类型是聚合, direct-list-initialization 将执行聚合初始化。 §8.5.4/ 3 [dcl.init.list]
braced-init-list 元素的评估顺序是从左到右。 §8.5.4/ 4 [dcl.init.list]
使用 direct-list-initialization
struct foo{};
struct bar
{
bar(foo const&) {}
};
bar b1(foo()); // most vexing parse
bar b2(foo{}); // all 3 of the following construct objects of type bar
bar b3{foo()};
bar b4{foo{}};
答案 1 :(得分:2)
Object obj(args...)
和Object{args...}
的行为取决于Object
中定义的构造函数。
采用以下示例:
#include <iostream>
#include <initializer_list>
struct A
{
A(int a, int b) {std::cout << "Came to A::A()\n";}
};
struct B
{
B(int a, int b) {std::cout << "Came to B::B(int, int)\n";}
B(std::initializer_list<int> in) {std::cout << "Came to B::B(std::initializer_list<int>)\n";}
};
int main()
{
A a1(10, 20); // Resolves to A(int, int)
A a2{10, 20}; // Resolves to A(int, int)
A a3{30}; // Does not resolve to anything. It's a compiler error.
B b1(10, 20); // Resolves to B(int, int)
B b2{10, 20}; // Resolves to B(std::initializer_list<int> )
B b3{30}; // Resolves to B(std::initializer_list<int> )
}
答案 2 :(得分:1)
Object obj(args ...)和Object obj {args ...}之间的区别是什么?为什么斯科特这么说。
不同之处在于,在前一种情况下,论证的评价顺序是无序的(即未指明),但在后一种情况下,顺序是从左到右(即它们出现)。
$ 5.2.2 / 8 [expr.call](n3690)中的以下文字涉及Object(args...)
表格:
后缀表达式和参数的评估都是相对于彼此的未序列。在输入函数之前,参数评估的所有副作用都会被排序(参见1.9)。
来自$ 8.5.4 / 4 [dcl.init.list](n3690)的文字涉及Object{args...}
表格:
在braced-init-list的初始化列表中, initializer-clause,包括包扩展产生的任何条款 (14.5.3),按照它们出现的顺序进行评估。那是, 每个值计算和与给定相关的副作用 initializer-clause在每个值计算之前排序 与其后面的任何初始化子句相关联的副作用 以逗号分隔的初始化列表列表。[注意:这个 无论语义如何,评估排序都成立 初始化;例如,它适用于。的元素 initializer-list被解释为构造函数调用的参数, 即使通常没有排序限制 电话的参数。 - 结束说明]
这意味着:
int f() { static int i = 10; return ++i; } //increment the static int!
Object obj(f(), f()); //is it obj(11,12) or obj(12,11)? Unspecified.
Object obj{f(), f()}; //it is obj(11,12). Guaranteed.
请注意GCC (4.7.0 and 4.7.2) have a bug because of which {}
form doesn't work the way it should。我不确定它是否在当前版本中修复。
希望有所帮助。
答案 3 :(得分:1)
Object obj(args ...)和Object obj {args ...}之间有什么区别?
{args ...}更喜欢带有initializer_list的构造函数而非其他合法候选者。
std::vector<int> v(10); // vector of size 10
std::vector<int> v{10}; // vector initialized with a single element, (int) 10
另一方面,你放弃了隐含的缩小。
std::vector<int> v(10.5); // vector of size 10
std::vector<int> v{10.5}; // illegal - no compile
std::vector<float> v{10.5}; // vector initialized with a single element, (float) 10.5