考虑这些类:
#include <iostream>
#include <string>
class A
{
std::string test;
public:
A (std::string t) : test(std::move(t)) {}
A (const A & other) { *this = other; }
A (A && other) { *this = std::move(other); }
A & operator = (const A & other)
{
std::cerr<<"copying A"<<std::endl;
test = other.test;
return *this;
}
A & operator = (A && other)
{
std::cerr<<"move A"<<std::endl;
test = other.test;
return *this;
}
};
class B
{
A a;
public:
B (A && a) : a(std::move(a)) {}
B (A const & a) : a(a) {}
};
当创建一个B
,我总是有一个最佳的前进路径A
,右值的一次移动或左值的一份副本。
是否可以用一个构造函数达到相同的结果?在这种情况下问题不大,但是多个参数怎么办?我需要参数列表中所有可能出现的左值和右值的组合。
这不仅限于构造函数,还适用于函数参数(例如 setter)。
注意:这个问题严格来说是关于class B
; class A
存在只是为了可视化复制/移动调用是如何执行的。
“按值”方法是一种选择。它并不像您所拥有的那样优化,但只需要一次重载:
class B
{
A a;
public:
B (A _a) : a(move(_a)) {}
};
对于左值和 x 值来说,成本都是 1 次额外的移动构造,但这对于纯右值来说仍然是最佳的(1 次移动)。 “xvalue”是已使用 std::move 转换为右值的左值。
您也可以尝试“完美转发”解决方案:
class B
{
A a;
public:
template <class T,
class = typename std::enable_if
<
std::is_constructible<A, T>::value
>::type>
B (T&& _a) : a(std::forward<T>(_a)) {}
};
这将使您回到复制/移动结构的最佳数量。但是您应该限制模板构造函数,使其不会过于通用。您可能更喜欢使用 is_convertible 而不是 is_constructible,就像我上面所做的那样。这也是单个构造函数解决方案,但随着您添加参数,您的约束变得越来越复杂。
Note:上面的约束是必要的,因为如果没有,客户B
当他们查询时会得到错误的答案std::is_constructible<B, their_type>::value
。如果没有适当的约束,它会错误地回答 trueB
.
我想说的是,这些解决方案并不总是比其他解决方案更好。这里需要进行工程权衡。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)