c++ - 构造函数继承和直接成员初始化

标签 c++ c++11 gcc constructor

<分区>

我正在尝试结合使用 C++ 11 直接数据成员初始化和“使用”语法来继承基类的构造函数。现在使用 gcc 5.4.0(在 Ubuntu 16.04 上)我观察到一个奇怪的错误,如果数据成员类型没有默认构造函数。查看以下最小示例时可能最容易理解:

#include <iostream>

struct Foo {
  Foo(int arg) { std::cout << "Foo::Foo(" << arg << ")" << std::endl; }
};

struct Base {
  Base(int arg) { std::cout << "Base::Base(" << arg << ")" << std::endl; }
};

struct Derived : public Base {
  using Base::Base;
  Foo foo{42};
};

int main() {
  Derived derived{120};
}

此代码通过 clang 以预期的行为编译和执行。使用 gcc 它不编译,因为编译器删除了构造函数 Derived::Derived(int):

ttt.cpp: In function ‘int main()’:
ttt.cpp:17:22: error: use of deleted function ‘Derived::Derived(int)’
   Derived derived{120};
                      ^
ttt.cpp:12:15: note: ‘Derived::Derived(int)’ is implicitly deleted because the default definition would be ill-formed:
   using Base::Base;
               ^
ttt.cpp:12:15: error: no matching function for call to ‘Foo::Foo()’
ttt.cpp:4:3: note: candidate: Foo::Foo(int)
   Foo(int arg) { std::cout << "Foo::Foo(" << arg << ")" << std::endl; }
   ^
ttt.cpp:4:3: note:   candidate expects 1 argument, 0 provided
ttt.cpp:3:8: note: candidate: constexpr Foo::Foo(const Foo&)
 struct Foo {
        ^
ttt.cpp:3:8: note:   candidate expects 1 argument, 0 provided
ttt.cpp:3:8: note: candidate: constexpr Foo::Foo(Foo&&)
ttt.cpp:3:8: note:   candidate expects 1 argument, 0 provided

如果我像这样向 Foo 添加默认构造函数:

  Foo() { std::cout << "Foo::Foo()" << std::endl; };

gcc 也可以编译。代码的行为完全相同,特别是添加的 Foo 默认构造函数永远不会执行。

所以我现在的问题是,这是有效的 C++ 11 吗?如果是,我可能在 gcc 中发现了一个错误。否则,gcc 和 clang 难道不应该给我一条错误消息,指出这不是有效的 C++ 11 吗?

在@vlad-from-moscow 很好地回答问题后进行编辑:这个错误似乎也存在于 gcc 6.2 中,所以我将提交错误报告。

第二次编辑:已经有一个错误,我在第一次搜索中没有找到:https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67054

最佳答案

gcc 不满足 C++ 标准。 Derived 类的继承构造函数应使用为 Derived 继承构造函数指定的参数调用其内存初始化器列表中的 Base 构造函数。

C++标准中有写(12.9 Inheriting constructor)

8 An inheriting constructor for a class is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8). An implicitly-defined inheriting constructor performs the set of initializations of the class that would be performed by a user-written inline constructor for that class with a mem-initializer-list whose only mem-initializer has a mem-initializer-id that names the base class denoted in the nested-name-specifier of the using-declaration and an expression-list as specified below, and where the compound-statement in its function body is empty (12.6.2). If that user-written constructor would be ill-formed, the program is ill-formed. Each expression in the expression-list is of the form static_cast(p), where p is the name of the corresponding constructor parameter and T is the declared type of p.

同样根据部分(12.6.2 初始化基地和成员)

8 In a non-delegating constructor, if a given non-static data member or base class is not designated by a mem-initializer-id (including the case where there is no mem-initializer-list because the constructor has noctor-initializer) and the entity is not a virtual base class of an abstract class (10.4), then

— if the entity is a non-static data member that has a brace-or-equal-initializer, the entity is initialized as specified in 8.5;

关于c++ - 构造函数继承和直接成员初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52646077/

相关文章:

xcode - 为什么安装 Xcode 命令行工具会改变 'gcc --version' 报告的内容

C++ 模板声明顺序

C++ 运行时终止 std::out_of_range

C++字符串流忽略()不起作用

c++ - 关于复制构造函数和 NRVO

c++ - 使用 boost 实现 C++11 lambda

c++ - 如何使用命令行在 C++ 中编译和链接分离的 .h 和 .cpp 文件?

c++ - std::move 已经是 T&& 的变量

c++ - 如何正确使用可变参数模板的引用

c++ - 基类嵌套类的外联定义