对于两个T
和U
类型的任意对象,它们组成一个类似的类
template <class T, class U>
struct Comp
{
T t_m;
U u_m;
};
从(可用的)临时工作中构建它们的最佳方式(就最小化复制操作而言)是什么?
我考虑过&#34;移动&#34;他们进入我的班级
Comp(T&& t, U&& u)
: t_m(std::move(t))
, u_m(std::move(u))
{ }
但我不知道他们的移动构造者表现得如何或者他们是否有任何。
由于我的类似乎可以是一个聚合,我想知道是否删除构造函数并允许aggregate initialization是一个更好的解决方案,即编写这样的代码:
Comp{ get_temporary_T(), get_temporary_U() };
或者使用direct initialization是否有优势。
现场施工(使用安置新操作员)不是我正在寻找的解决方案。
我想std::tuple
使用这样一种最佳方法,因为make_tuple
通过调用元组构造函数显示利用临时:
auto t = std::make_tuple(10, "Test", 3.14, std::ref(n), n);
或许有人会详细说明如何做到这一点?
答案 0 :(得分:2)
这已经是最佳选择了:
Comp(T&& t, U&& u)
: t_m(std::move(t))
, u_m(std::move(u))
{ }
如果T
有一个移动构造函数,那么这将是一个移动。如果它没有,那么这将是一个副本 - 但是那时无法在某个地方制作副本。而且它不可复制,那么整个问题都没有实际意义。
当然这只适用于右值,所以你也想要一些左手的东西。不幸的是,这有点复杂:
template <class Tx, class Ux,
class = std::enable_if_t<std::is_convertible<std::decay_t<Tx>*, T*>::value &&
std::is_convertible<std::decay_t<Ux>*, U*>::value>>
Comp(Tx&& t, Ux&& u)
: t_m(std::forward<Tx>(t))
, u_m(std::forward<Ux>(u))
{ }
在这里,我们希望允许扣除Tx
,使其T
,T&
或D
,D&
其中D
1}}派生自T
。 std::decay
删除引用,并is_convertible
用于指针检查,如果它是派生的。
好的,我们可以做得更好吗?并不是的。这要么是为每个成员做1次移动,要么是1份。但是如果我们想要将它们构建到位呢?我们应该允许:
template <class... TArgs, class... UArgs,
class = std::enable_if_t<std::is_constructible<T, TArgs...>::value &&
std::is_constructible<U, UArgs...>::value>>
Comp(std::piecewise_construct_t pc, std::tuple<TArgs...> const& t, std::tuple<UArgs...> const& u)
: Comp(t, u, std::index_sequence_for<TArgs...>{}, std::index_sequence_for<UArgs...>{})
{ }
private:
template <class TTuple, class UTuple, size_t... Is, size_t... Js>
Comp(TTuple const& t, UTuple const& u, std::index_sequence<Is...>, std::index_sequence<Js...> )
: t_m(std::get<Is>(t)...)
, u_m(std::get<Js>(u)...)
{ }
有了这个,我们可以通过就地构建来避免任何类型的复制或移动。这是否有益取决于您对Comp
的使用情况。
答案 1 :(得分:1)
你使用移动构造函数的命题似乎是最好的方法。
在处理临时对象时,最好的事情(以及最优化的)是在成员中移动参数。但正如你所说,移动构造函数可能不存在。
如果只有一个参数,则很容易检查它是否可移动构造并移动它并以其他方式复制它。您可以将std::enable_if
与std::is_move_constructible
一起使用。
但是如果有超过1个参数,则必须检查所有组合。例如,对于2个参数,您必须具有4个构造函数:复制/复制,移动/复制,复制/移动和移动/移动。因此它不具有真正的可扩展性,因此更适合复制参数。
使用聚合初始化,参数是复制不移动。