2014-07-13 54 views
7

书草案Effective C++11斯科特迈尔斯指出:`Object obj(args ...)`和`Object obj {args ...}`有什么区别?

区分()和{}创建对象

什么Object obj(args...)Object obj{args...}之间的区别是什么时候?为什么斯科特这么说。

更新:

问题How to use C++11 uniform initialization syntax?询问怎么了,这个问题是问为什么。

UPDATE2:

我发现下面的链接是有益的,完全回答了这个问题:

https://softwareengineering.stackexchange.com/questions/133688/is-c11-uniform-initialization-a-replacement-for-the-old-style-syntax

+0

可能重复的[如何使用C++ 11均匀初始化语法?](http://stackoverflow.com/questions/7612075/how-to-use-c11-uniform-initialization-syntax) –

+0

@MattMcNabb,这个问题问如何,这个问题问为什么。 – xmllmx

+5

这个问题不问“为什么”,另一个问题涉及统一初始化的作用。 –

回答

5

什么Object obj(args...)Object obj{args...}之间的区别?

首先是直接初始化而第二个是直接列表初始化。这在两个不同的部分中提到:

第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]

列表初始化是从支撑-INIT列表对象或参考的初始化。这种初始化器被称为初始化器列表,并且列表的逗号分隔的子句被称为初始化器列表的元件。初始化程序列表可能为空。 列表初始化可以发生在直接初始化或复制初始化上下文中;在直接初始化上下文中的列表初始化被称为直接列表初始化并且复制初始化上下文中的列表初始化被称为复制列表初始化


有两个之间的一些区别:

  • 如果正在构建的类型有一个构造函数的initializer_list说法,直接列表初始化永远青睐的是构造函数。其他构造函数仅在initializer_list构造函数不可用时才会被考虑。 §13.3.1.7/ 1 [over.match.list]

  • 直接一览初始化不允许参数列表内缩小转换。 §8.5.4/ 3 [dcl.init.list]

  • 如果被初始化的类型是一个聚集,直接一览初始化将执行集合初始化。 §8.5.4/ 3 [dcl.init.list]

  • 一个支撑-INIT列表是从左至右的元件的评价的顺序。 §8.5.4/ 4 dcl.init.list]

  • 您可以通过使用直接列表初始化

 

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

什么是obj对象之间的差异(参数...)和对象OBJ {ARGS ...}?为什么斯科特这么说。

的区别是,前者情况下,参数计算顺序是未测序(即未指定的),但在后一种情况下,顺序为从左向右(即它们出现)。

从$ 5.2.2/8下面的文本[expr.call](n3690)与Object(args...)形式涉及:

后缀表达式的和的参数的评价都是未测序相对于一个另一个。参数评估的所有副作用在输入函数之前进行排序(见1.9)。

而且从$ 8.5.4/4文本[dcl.init.list(n3690)与Object{args...}形式的交易:

在一个支撑,初始化列表的初始化列表中, 初始化子句,包括从包扩展 (14.5.3)导致的任何结果,都是,按它们出现的顺序评估。也就是 在给定的 初始化子句关联的每个值计算和副作用在每个值计算和 副作用与在初始化程序列表的逗号分隔列表 之后的任何初始化子句关联。 [注意:无论 初始化的语义如何,此 评估顺序都成立;例如,当 初始化程序列表的元素被解释为构造函数调用的参数 时,即使通常在调用的参数 上没有排序约束,也适用。 - 注完]

那么这意味着这样的:

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。我不确定它是否在当前版本中修复。

希望有所帮助。

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>) 

} 
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 
相关问题