【问题标题】:Move only class parameter in inherited constructor在继承的构造函数中只移动类参数
【发布时间】:2016-09-01 02:11:12
【问题描述】:

以下代码不能编译GCC 6.1,但可以在Clang 3.8.0 和Visual Studio 2015 中工作:

#include <memory>

class base {
public:
    base(std::unique_ptr<int>) {}
};

class derived : public base {
public:
    using base::base;
};

int main() {
    derived df(std::make_unique<int>());
}

出现以下错误:

main.cpp: In constructor 'derived::derived(std::unique_ptr<int>)':

main.cpp:10:17: error: use of deleted function 
'std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) 
[with _Tp = int; _Dp = std::default_delete<int>]'

     using base::base;

                 ^~~~

In file included from /usr/local/include/c++/6.1.0/memory:81:0,

                 from main.cpp:1:

/usr/local/include/c++/6.1.0/bits/unique_ptr.h:356:7: note: declared here

       unique_ptr(const unique_ptr&) = delete;

       ^~~~~~~~~~

main.cpp: In function 'int main()':

main.cpp:14:39: note: synthesized method 'derived::derived(std::unique_ptr<int>)' 
first required here 

     derived df(std::make_unique<int>());

它似乎正在尝试调用已删除的复制构造函数,但这工作得很好:

void foo(std::unique_ptr<int>) {}

int main() {
    foo(std::make_unique<int>());
}

这个带有-fno-elide-constructors 的示例打印出move called.:

struct move_only {
    move_only() { std::cout << "default called."; }
    move_only(move_only&&) { std::cout << "move called."; }
};

void foo(move_only) { }

int main() {
    foo(move_only{});
}

我意识到这两种情况并不相同,但似乎很奇怪&amp;&amp; 需要编译继承的构造函数示例而不是后者。作为健全性检查,显式执行move_only(const move_only&amp;) = delete; 并将签名更改为void foo(const move_only&amp;) { } 仍然可以编译,除了这次甚至没有调用移动构造函数(可能是省略)。

12.6.3的最新标准草案说:

1 当调用B 类型的构造函数来初始化对象时 不同类型的D(即,当构造函数被继承时 ([namespace.udecl])),初始化就像默认的 默认构造函数用于初始化 D 对象和每个基 继承构造函数的类子对象,除了 B 子对象由继承的调用初始化 构造函数。完整的初始化被认为是一个单一的 函数调用;特别是继承的初始化 构造函数的参数在任何初始化之前排序 D 对象的一部分。 [ 例子:

struct B1 {
  B1(int, ...) { }
};

// ...

struct D1 : B1 {
  using B1::B1;  // inherits B1(int, ...)
  int x;
  // ...
};

void test() {
  D1 d(2, 3, 4); // OK: B1 is initialized by calling B1(2, 3, 4),
                 // then d.x is default-initialized (no initialization is performed),
  // ...
}

// ...

所以它应该完全等同于foo(move_only) 对吧?

【问题讨论】:

  • 继承构造函数语义在当前工作草案中经历了a giant overhaul;还没有人实施新版本。
  • 看起来像是 g++ 6.1 中的回归。 It compiles 在 g++5.3 中

标签: c++ gcc c++14 move-semantics


【解决方案1】:

这似乎是一个错误(报告为bug 70972)。 N4140 [class.inhctor]/8:

一个隐式定义的继承构造函数执行一组 将由用户编写的类的初始化 具有 mem-initializer-list 的该类的内联构造函数,其 只有 mem-initializer 有一个 mem-initializer-id 来命名基础 using-declaration 的 nested-name-specifier 中表示的类 和一个如下指定的表达式列表,其中 compound-statement 在其函数体中是空的 (12.6.2)。如果说 用户编写的构造函数格式错误,程序是 格式不正确。 expression-list 中的每个 expression 的格式为 static_cast&lt;T&amp;&amp;&gt;(p),其中p是对应的名称 构造函数参数和T是p的声明类型。

换句话说,这里讨论的继承构造函数应该是移动而不是复制它的参数。

【讨论】:

    猜你喜欢
    • 2013-02-27
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 2011-12-08
    • 1970-01-01
    • 2023-03-14
    • 2015-12-02
    • 2014-03-08
    相关资源
    最近更新 更多