初始化的差异不仅在于其形式,还在于被初始化的实体类型。在这种情况下,它是一个具有定义好的默认构造函数和带参数构造函数的类类型对象。
Entity ent1;
上述语句是默认初始化,导致调用类
Entity
的默认构造函数。
Entity ent2();
如果可能的话,编译器会将上述声明视为函数原型。
Entity
将是函数
ent2
的返回类型,该函数不带参数。这被称为最棘手的解析(MVP)之一,其存在导致出现了误导性的“聪明愚蠢规则”:“永远不要使用括号”。
在这样的语句中,与参数列表匹配的用户定义构造函数将为ent3
对象调用:
Entity ent3(1, 2); // calls Entity(int x, int y)
MVP 可以发挥作用的另一个案例是这样的:
Entity ent3_1(int(a), int(b)); // It's not what it looks like.
ent3_1
不是一个变量。这个语句声明了一个具有两个int参数的函数。int(a)
和int a
相同,是C语言和声明语法的遗留问题,它忽略了“额外”的括号。
Entity ent4 = Entity();
ent4
是 C++11 之前 ent2
案例的一个适当的版本。默认构造函数是作为值初始化的一部分被调用的。它的形式允许避免解决原则的歧义,从而使ent2
和ent3_1
不正确。等号在这里不是赋值,因为没有operator=
的调用发生。它是声明语法的一部分,旨在标记初始化表达式。
Entity ent5 = Entity(2, 3);
ent5
是 ent3 情况的一个版本。用户定义的构造函数作为值初始化的一部分被调用。
你的问题标记为C++11,而C++11允许使用统一的初始化语法:
Entity ent12{}; // This is a legal alternative of ent2 case
Entity ent13{1, 2}; // A call to constructor or member initialization
Entity ent13{ int(a), int(b) }; // Not a function anymore
Entity ent14 = {}; // Not an assignment
Entity ent15 = Entity{2, 3}; // Not an assignment either!
请注意,统一初始化语法有一个警告。例如,这行代码:
std::vector<int> v(10)
声明了一个包含10个元素的向量。但是这个{{one}}
std::vector<int> v{10}
声明一个类型为int且值为10的单元素向量。这是因为std::vector
定义了以下签名的构造函数:
vector( std::initializer_list<T> init, const Allocator& alloc = Allocator() );
如果您无法使用()而不触发MVP,也无法使用{}而不调用不需要的构造函数,则值初始化赋值语法可以解决此问题。
附录:必看
CppCon 2018:Nicolai Josuttis“C ++中初始化的噩梦”
Entity ent2();
是一个函数声明。 - tkauslent2
的函数,其返回值类型为Entity
。 - Arnav Borborah