为什么 C++11 类内初始化器不能使用括号?
例如,我不能这样写:
class A
{
vector<int> v(12, 1);
};
我只能这样写:
class A
{
vector<int> v1{ 12, 1 };
vector<int> v2 = vector<int>(12, 1);
};
C++11 语言设计的差异有何考虑?
What's the consideration for the differences in C++11 language design?
推荐答案
一个可能的原因是允许使用括号会让我们回到 最令人烦恼的解析.考虑以下两种类型:
One possible reason is that allowing parentheses would lead us back to the most vexing parse in no time. Consider the two types below:
struct foo {};
struct bar
{
bar(foo const&) {}
};
现在,您有一个 bar
类型的数据成员要初始化,因此将其定义为
Now, you have a data member of type bar
that you want to initialize, so you define it as
struct A
{
bar B(foo());
};
但是你在上面所做的是声明一个名为 B
的函数,它按值返回一个 bar
对象,并接受一个具有签名的函数的参数 foo()
(返回一个 foo
并且不带任何参数).
But what you've done above is declare a function named B
that returns a bar
object by value, and takes a single argument that's a function having the signature foo()
(returns a foo
and doesn't take any arguments).
从 StackOverflow 上针对此问题提出的问题的数量和频率来看,这是大多数 C++ 程序员感到惊讶和不直观的事情.添加新的 brace-or-equal-initializer 语法是避免这种歧义并从头开始的机会,这可能是 C++ 委员会选择这样做的原因.
Judging by the number and frequency of questions asked on StackOverflow that deal with this issue, this is something most C++ programmers find surprising and unintuitive. Adding the new brace-or-equal-initializer syntax was a chance to avoid this ambiguity and start with a clean slate, which is likely the reason the C++ committee chose to do so.
bar B{foo{}};
bar B = foo();
上面的两行都声明了一个名为 B
的对象,类型为 bar
,正如预期的那样.
Both lines above declare an object named B
of type bar
, as expected.
除了上面的猜测之外,我想指出的是,在上面的示例中,您正在做两件截然不同的事情.
Aside from the guesswork above, I'd like to point out that you're doing two vastly different things in your example above.
vector<int> v1{ 12, 1 };
vector<int> v2 = vector<int>(12, 1);
第一行将 v1
初始化为包含两个元素 12
和 1
的向量.第二个创建一个包含 12
元素的向量 v2
,每个元素都初始化为 1
.
The first line initializes v1
to a vector that contains two elements, 12
and 1
. The second creates a vector v2
that contains 12
elements, each initialized to 1
.
注意这个规则――如果一个类型定义了一个接受 initializer_list
的构造函数,那么当该类型的构造函数总是被首先考虑是一个 braced-init-list.仅当采用 initializer_list
的构造函数不可行时,才会考虑其他构造函数.
Be careful of this rule - if a type defines a constructor that takes an initializer_list<T>
, then that constructor is always considered first when the initializer for the type is a braced-init-list. The other constructors will be considered only if the one taking the initializer_list
is not viable.
相关文章