为什么C ++ 11不支持在构造函数初始化列表中的初始化? [英] Why doesn't C++11 curly brace initialzation in constructor initialization list work when parens initializaton does?
问题描述
初始化抽象类型的引用时,构造函数初始化列表中的{}初始化是如何不同于初始化的?下面的类Bar:
How is {} initialization in a constructor initialization list different from () initialization when initializing reference to abstract types? Take class Bar below:
class AbstractBase
{
public:
AbstractBase() {}
virtual ~AbstractBase() = default;
virtual void ab() = 0;
};
class Foo : public AbstractBase
{
public:
Foo() {}
void ab() {}
};
class Bar
{
public:
Bar(const AbstractBase& base) : myBase{base} {}
private:
const AbstractBase& myBase;
};
int main()
{
Foo f{};
Bar b{f};
}
编译时出现错误
test5.cpp: In constructor ‘Bar::Bar(const AbstractBase&)’:
test5.cpp:22:48: error: cannot allocate an object of abstract type ‘AbstractBase’
Bar(const AbstractBase& base) : myBase{base}
^
test5.cpp:2:7: note: because the following virtual functions are pure within ‘AbstractBase’:
class AbstractBase
^
test5.cpp:8:18: note: virtual void AbstractBase::ab()
virtual void ab() = 0;
更改行
Bar(const AbstractBase& base) : myBase(base) {}
通过阅读Stroustrup的C ++ 11书,我的印象是{}在大多数情况下与()相同,除非在使用std :: initializer_list<>和其他构造函数的构造函数之间存在模糊性,以及使用auto作为类型的情况,我都不在这里。
Reading through Stroustrup's C++11 book, I was under the impression that {} was the same as () in most all cases, except where there was an ambiguity between constructors that take std::initializer_list<> and other constructors, and cases where using auto as the type, neither of which I'm doing here.
推荐答案
简短答案:这是一个在C ++ 14中修复的标准错误,而g ++ 4.9有修复(追溯应用于C ++ 11模式)。 缺陷报告1288
Short answer: This was a bug in the Standard which is fixed in C++14, and g++ 4.9 has the fix (retroactively applied to C++11 mode too). Defect Report 1288
这里有一个更简单的例子:
Here's a simpler example:
struct S
{
int x;
S() { } // this causes S to not be an aggregate (otherwise aggregate
// initialization is used instead of list initialization)
};
S x = 5;
S const &y { x } ;
x = 6;
std::cout << y << std::endl; // output : 5
在C ++ 11的文本中, S const& y {x};
不要将 y
绑定到 x
;其实意思是创建一个临时并绑定一个引用。从C ++ 11 [dcl.init.ref] / 3:
In the text of C++11, the meaning of S const &y {x};
is not to bind y
to x
; in fact the meaning is to create a temporary and bind a reference to that. From C++11 [dcl.init.ref]/3:
否则,如果T是引用类型,由T引用的类型的prvalue临时是列表初始化的,并且引用绑定到该临时。 [注意:像往常一样,如果引用类型是非const类型的左值引用,则绑定将失败,程序不成形。 -end note]
Otherwise, if T is a reference type, a prvalue temporary of the type referenced by T is list-initialized, and the reference is bound to that temporary. [Note: As usual, the binding will fail and the program is ill-formed if the reference type is an lvalue reference to a non-const type. —end note ]
这很傻,显然这个代码的意图是绑定 y
直接到
x
。在C ++ 14中,文本已更改:
This is pretty silly , clearly the intent of this code is to bind y
directly to x
. In C++14 the text was changed:
否则,如果初始化器列表有一个E类型的元素,引用类型或其引用类型与E引用相关,对象或引用从该元素初始化;
Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its referenced type is reference-related to E, the object or reference is initialized from that element;
是与自身(或其基类之一)相关的引用,在我的样例中和你的实际代码中,它应该实际绑定正确。
Since a type is reference-related to itself (or one of its base classes), in my sample here and in your actual code, it should actually bind correctly.
您的错误消息来自编译器遵循C ++ 11字样,并试图从 base
创建一个临时表,以将引用绑定到;并且此操作失败,因为 base
是抽象类型。
Your error message comes from the compiler following the C++11 wording and attempting to create a temporary from base
to bind the reference to; and this fails because base
is of an abstract type.
这篇关于为什么C ++ 11不支持在构造函数初始化列表中的初始化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!