#include <utility>
#include <iostream>
template<typename A, typename B>
using disable_if_same_or_derived =
std::enable_if_t<
!std::is_base_of<
A,
std::remove_reference_t<B>
>::value
>;
template<class T>
class wrapper {
public:
// perfect forwarding ctor in order not to copy or move if unnecessary
template<
class T0,
class = disable_if_same_or_derived<wrapper,T0> // do not use this instead of the copy ctor
> explicit
wrapper(T0&& x)
: x(std::forward<T0>(x))
{}
private:
T x;
};
class trace {
public:
trace() {}
trace(const trace&) { std::cout << "copy ctor\n"; }
trace& operator=(const trace&) { std::cout << "copy assign\n"; return *this; }
trace(trace&&) { std::cout << "move ctor\n"; }
trace& operator=(trace&&) { std::cout << "move assign\n"; return *this; }
};
int main() {
trace t1;
wrapper<trace> w_1 {t1}; // prints "copy ctor": OK
trace t2;
wrapper<trace> w_2 {std::move(t2)}; // prints "move ctor": OK
wrapper<trace> w_3 {trace()}; // prints "move ctor": why?
}
我希望我的wrapper
没有任何开销。特别是,在将临时变量转换为包装器时,例如w_3
,我希望trace
对象直接就地创建,而不必调用移动构造函数。然而,实际上存在一个移动构造函数调用,这让我想到可能创建了一个临时变量并进行了移动。为什么会调用移动构造函数?如何避免调用它?
&w_3.x
的位置神奇地构造临时对象。我认为这是不可能的。虽然有返回值优化,但没有参数优化。换句话说,在wrapper
构造函数中,&x != &(this->x)
。你可以像std::vector::emplace
一样做-拥有一个接受任意参数的构造函数,并将它们传递给x
的构造函数。 - Igor Tandetnikw_3.x
是一个 lvalue。在这两者之间,必须发生某种形式的复制或移动。 - Igor Tandetnik