DataWrapperByValue::data_
is moved from DataWrapperByValue::DataWrapperByValue(Data data)
s arguement data
which is moved in from d2
.
Your conclusion to pass-by-rvalue-reference together with a by value version for cases where you get an l-value yields the best performance. However this is widely considered premature optimization. Howard Hinnant (Best way to write constructor of a class who holds a STL container in C++11) and Sean Parent (http://channel9.msdn.com/Events/GoingNative/2013/Inheritance-Is-The-Base-Class-of-Evil) have both noted that they consider this premature optimization. The reason is that moves are supposed to be verry cheap and to avoid them in this case would cause code duplication, especially if you have more than one arguement that can either be an r or l-value. If by profileing or testing you find that this actuall does degrade performance you can always easily add the pass-by-rvalue-reference after the fact.
A useful pattern in a case where you do need the extra performance is:
struct DataWrapperByMoveOrCopy {
Data data_;
template<typename T,
typename = typename std::enable_if< //SFINAE check to make sure of correct type
std::is_same<typename std::decay<T>::type, Data>::value
>::type
>
DataWrapperByMoveOrCopy(T&& data) : data_{ std::forward<T>(data) } { }
};
here the constructor always does the right thing as can be seen in my live example: http://ideone.com/UsltRA
The advantage of this argueably complex code is probably not relevant with a single arguement but imagine if your constructor had 4 arguements which could be r or l-values, this is much better than writing 16 different constructors.
struct CompositeWrapperByMoveOrCopy {
Data data_;
Foo foo_;
Bar bar_;
Baz baz_;
template<typename T, typename U, typename V, typename W,
typename = typename std::enable_if<
std::is_same<typename std::decay<T>::type, Data>::value &&
std::is_same<typename std::decay<U>::type, Foo>::value &&
std::is_same<typename std::decay<V>::type, Bar>::value &&
std::is_same<typename std::decay<W>::type, Baz>::value
>::type
>
CompositeWrapperByMoveOrCopy(T&& data, U&& foo, V&& bar, W&& baz) :
data_{ std::forward<T>(data) },
foo_{ std::forward<U>(foo) },
bar_{ std::forward<V>(bar) },
baz_{ std::forward<W>(baz) } { }
};
Note that you can omit the SFINAE check but this allows subtle problems like implicitly converting using explicit constructors. Also without checking the argument types conversions are deferred to inside the consttructor where there are different access rights, different ADL etc. see live example: http://ideone.com/yb4e3Z