6

假设我有一个unique_ptr要在类中初始化的成员对象,请参见下面的代码。为什么我必须使用统一初始化(花括号)?第二个声明吐出一个错误,比如

so.cpp:10:31: error: expected parameter declarator
std::unique_ptr<Foo> upf2(new Foo);
                          ^
so.cpp:10:31: error: expected ')'
so.cpp:10:30: note: to match this '('
std::unique_ptr<Foo> upf2(new Foo);                             ^
2 errors generated. 

而且我不认为这是一个最令人头疼的解析问题,至少我不这么认为。

#include <memory>

class Foo
{

};

class Bar{
    std::unique_ptr<Foo> upf1{new Foo}; // works fine
//    std::unique_ptr<Foo> upf2(new Foo); // error here
};

int main() 
{
    Bar bar;
}
4

2 回答 2

9

因为那是规则。类内初始化器必须使用“大括号”或“等号”;实际上,句法元素称为大括号或相等初始化器

int equals = 42;                      // OK
std::unique_ptr<Foo> braces{new Foo}; // Also OK

我不知道为什么不允许使用括号;也许是为了避免初始化看起来像函数声明的可能性。当直接初始化和大括号初始化之间存在差异时可能会很烦人:

std::vector<int> bad(6);                     // ERROR: parentheses not allowed
std::vector<int> good{6};                    // OK but not the same
std::vector<int> ugly = std::vector<int>(6); // OK but ugly
于 2014-10-09T02:38:02.303 回答
8

非静态数据成员初始化器 (NSDMI) 必须使用大括号或相等初始化器( expression-list )不允许初始化的形式。

正如N2756解释的那样,为了让 NSDMI 的行为更像传统的构造函数成员初始化列表,初始化器内部的名称在整个类的范围内查找。不幸的是,这意味着允许括号初始化器将无法在解析声明时确定某个东西是初始化器还是函数声明:

// not real code
struct X {
    int i(x);    // initializer
    static int x;
};

struct Y {
    int i(x);    // function
    typedef int x;
};

该论文讨论了几种可能的方法来解决这个问题,而不是完全禁止它(“所有可以是声明的东西都是声明”或“除非你说它是类型,否则它不是类型”),但都不是很吸引人,而且潜在的混乱被认为超过了允许这种初始化形式的好处。

于 2014-10-09T02:42:00.867 回答