动态对象的统一初始化

3
#include <memory>

struct foo
{
    std::unique_ptr<int> p;
};

int main()
{
    foo bar { std::unique_ptr<int>(new int(42)) };
    // okay

    new foo { std::unique_ptr<int>(new int(42)) };
    // error: no matching function for call to
    // 'foo::foo(<brace-enclosed initializer list>)'
}

动态对象是否不支持统一初始化,或者这是g++ 4.6.1的缺陷?
它可以在g++ 4.7.1中工作,但是如果foo继承另一个类,则main中的两行都无法编译:
struct baz
{
    // no data members, just some member functions
};

struct foo : baz
{
    std::unique_ptr<int> p;
};

再次出现编译器的缺陷?还是统一初始化与继承不兼容?


1
new foo({std::unique_ptr<int>(new int(42))}); 这个在4.6.1版本中可以正常工作。 - jrok
@jrok 这是否意味着我使用的语法(没有额外的括号)在某种程度上是次优、不符惯用法甚至是“错误”的? - fredoverflow
之前有一个类似的问题,但我找不到了。如果我没记错的话,结论是这是一个 bug。 - jrok
3个回答

4

使用g++-4.7编译可以成功构建。所以很可能是后者的问题。我会查看文档,看是否能找到更强的证据。

针对继承补充的回答:

这个简单的例子也无法编译通过:

struct baz
{
};

struct foo : baz
{
    int b;
};

int main()
{
    foo bar { 12 };
}

使用:

testoo.cpp:14:18: error: no matching function for call to ‘foo::foo(<brace-enclosed initializer list>)’
testoo.cpp:14:18: note: candidates are:
testoo.cpp:7:8: note: foo::foo()
testoo.cpp:7:8: note:   candidate expects 0 arguments, 1 provided
testoo.cpp:7:8: note: constexpr foo::foo(const foo&)
testoo.cpp:7:8: note:   no known conversion for argument 1 from ‘int’ to ‘const foo&’
testoo.cpp:7:8: note: constexpr foo::foo(foo&&)
testoo.cpp:7:8: note:   no known conversion for argument 1 from ‘int’ to ‘foo&&’

根据我对标准的理解,你在第一个示例中使用了“聚合初始化”:
聚合是指没有用户提供构造函数(12.1),非静态数据成员没有花括号或等号初始化器(9.2),没有私有或保护的非静态数据成员(第11条),没有基类(第10条),也没有虚函数(10.3)的数组或类(第9条)。 当聚合通过初始化器列表进行初始化时,如8.5.4中所指定的那样,初始化器列表的元素按照下标或成员顺序递增地作为聚合的成员的初始值。
需要注意的是,这明确禁止基类。因此,总结一下 - 在存在基类的情况下不允许使用聚合初始化。因此,第二个示例都无法编译。

理论上这可能是一种退步。但是,不太可能。 - Konrad Rudolph
@KonradRudolph 说得好。我正在尝试在g++发行说明中找到一些相关文档,但是迄今为止还没有找到。 - Alex Wilson
@Alex,如果你感兴趣的话,我已经给我的问题增加了另一个变化。 - fredoverflow
@FredOverflow:我已经尽我所能解析标准,并得出了答案... :-) - Alex Wilson

2

如果foo继承自另一个类,则main中的两行代码都无法编译通过。

啊,统一初始化对于聚合体和非聚合体有不同的工作方式:

类型为T的对象或引用的列表初始化定义如下:

  • 如果T是一个聚合体,则执行聚合初始化
  • [...]
  • 否则,如果T是一个类类型,则考虑构造函数

聚合体是[...]一个没有基类[...]和没有虚函数的类[...]。

因此,在我的情况下仍然需要编写自定义构造函数,因为我需要在这里使用子类型多态性。


所以,列表初始化和统一初始化这两个术语是相同的。它们并不不同,对吗? - Destructor

1

目前我手头上没有最终版本,但是草案N3242中的§ 8.5.4 列表初始化明确指出,列表初始化可以用作新表达式中的初始化器。它还提供了以下示例:

new std::vector<std::string>{"once", "upon", "a", "time"}; // 4 string elements

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接