为什么 C++11 类内初始化器不能使用括号?

2021-12-12 00:00:00 c++ 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 初始化为包含两个元素 121 的向量.第二个创建一个包含 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.

相关文章