【发布时间】: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; ...
};
但由于work1 是work_like 类,转发构造函数突然变得更好了,因为common_work 的复制/移动构造函数需要从派生到基类的static_cast。
注意:
- Scott Meyers 给出了类似的示例,其中复制构造触发转发构造函数,因为复制构造函数需要添加 const,而转发构造函数不需要。但我认为,这个问题是由于错误的类设计引起的,而这里的问题是由于在隐式复制/移动期间传递给基类的参数不完全匹配。
- 我不能编写通用转发构造函数/赋值,并删除隐式的,因为删除的函数也参与重载决议,如果完全匹配会导致错误。
- 目前我的解决方案是将
common_work设为CRTP,即作为模板参数传递的派生类类型,并在转发构造函数中将其过滤为enable_if<and_<work_like<T>,not_<is_same<T,Derived> > > >。否则,我必须手动将work1和static_cast的复制/移动构造函数/赋值显式地写入基类,这是错误的、容易出错且存在维护风险。
【问题讨论】:
-
也许您可以通过加强 SFINAE 约束来解决此问题,以便它拒绝派生自
common_work的Ts? -
这就是我目前所做的。查看注释部分的第 3 点。不过,它不应该是
is_same<T,Derived>,而是is_same<remove_ref<T>,Derived> -
好的,抱歉。我没有读最后一个注释:)
-
我无法在其他编译器上进行测试,但使用 G++ 4.7.2:test。如果您不定义(“用户提供”)复制 ctor,“转换为基础”似乎是由编译器隐式完成的......您可以在您的平台上测试示例吗?
标签: c++ c++11 constructor assignment-operator perfect-forwarding