【问题标题】:rationale behind c++ implicit copy and move constructor?C++ 隐式复制和移动构造函数背后的基本原理?
【发布时间】:2013-07-16 23:45:59
【问题描述】:

我对c++隐式拷贝构造函数的理解类似于

T(T const& x) : 
    base1(x), base2(x) ... , 
    var1(x.var1), var2(x.var2)...
{}

移动构造函数,复制和移动赋值也遵循类似的模式。

为什么没有像下面这样定义?

T(T const& x) : 
    base1(static_cast<base1 const&>(x)),
    base2(static_cast<base2 const&>(x)) ... , 
    var1(x.var1), var2(x.var2)...
{}

示例

我有一个具有隐式复制/移动构造函数/赋值运算符的类,以及一些转换构造函数。我正在将这项工作委托给某个实现类。

class common_work //common implementation of many work like classes
{
   common_work(common_work const&) = default;
   common_work(common_work&&) = default;// ... implicit constructors work for me.
   //a forwarding constructor which can take many work like objects
   template<class T, enable_if<work_like<T> > >
   common_work(T&& x) { ... }
};
class work1 //one of the implementation
{
   work1(work1 const& ) = default;
   work1(work1&& ) = default; ...
   common_work impl_;
};

这很好,因为work1 复制/移动构造函数正在为common_work 调用复制/移动构造函数,并且转发构造函数被其他构造函数使用[代码中未显示],它从另一种work 转换。

然后出于 EBO 和其他原因,我想从 common_work 继承 work1。所以新的work1 类看起来像

class work1 : private common_work
{
   work1(work1 const& ) = default;
   work1(work1&& ) = default; ...
};

但由于work1work_like 类,转发构造函数突然变得更好了,因为common_work 的复制/移动构造函数需要从派生到基类的static_cast

注意:

  • Scott Meyers 给出了类似的示例,其中复制构造触发转发构造函数,因为复制构造函数需要添加 const,而转发构造函数不需要。但我认为,这个问题是由于错误的类设计引起的,而这里的问题是由于在隐式复制/移动期间传递给基类的参数不完全匹配。
  • 我不能编写通用转发构造函数/赋值,并删除隐式的,因为删除的函数也参与重载决议,如果完全匹配会导致错误。
  • 目前我的解决方案是将common_work 设为CRTP,即作为模板参数传递的派生类类型,并在转发构造函数中将其过滤为enable_if&lt;and_&lt;work_like&lt;T&gt;,not_&lt;is_same&lt;T,Derived&gt; &gt; &gt; &gt;。否则,我必须手动将 work1static_cast 的复制/移动构造函数/赋值显式地写入基类,这是错误的、容易出错且存在维护风险。

【问题讨论】:

  • 也许您可以通过加强 SFINAE 约束来解决此问题,以便它拒绝派生自 common_workTs?
  • 这就是我目前所做的。查看注释部分的第 3 点。不过,它不应该是is_same&lt;T,Derived&gt;,而是is_same&lt;remove_ref&lt;T&gt;,Derived&gt;
  • 好的,抱歉。我没有读最后一个注释:)
  • 我无法在其他编译器上进行测试,但使用 G++ 4.7.2:test。如果您不定义(“用户提供”)复制 ctor,“转换为基础”似乎是由编译器隐式完成的......您可以在您的平台上测试示例吗?

标签: c++ c++11 constructor assignment-operator perfect-forwarding


【解决方案1】:

几年前在 MSVC++ bugtracker 页面上讨论了此问题(因此,如果尚未修复,则它是 MSVC++ 上的一个已知问题)。标准说

  • ...基数或成员直接用 x 的相应基数或成员初始化。

当我阅读错误报告时,我确实测试了各种编译器,并且所有这些编译器都“神奇地铸造了”。该标准似乎对细节(也关于值类别和 c/v 限定符)保持沉默,只是说“具有 x 的相应基数”,如果您认为它的意思是 IMO 更有意义“不是 x,而是 x 的相应基 ...”,而不是您将完整的对象传递给它(我什至会说它只能 以这种方式有意义) .

【讨论】:

  • 请注意,显式默认的特殊成员函数尚未在 MSVC 中实现(尽管他们表示将很快在 2013 RTM 中实现)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-07
  • 2011-06-17
  • 2021-06-01
  • 2023-03-11
  • 1970-01-01
  • 2018-03-12
相关资源
最近更新 更多