#include <iostream>
#include <type_traits>
struct Data {
Data() { std::cout << " constructor\n";}
Data(const Data& data) { std::cout << " copy constructor\n";}
Data(Data&& data) { std::cout << " move constructor\n";}
};
struct DataWrapperWithMove {
Data data_;
DataWrapperWithMove(Data&& data) : data_(std::move(data)) { }
};
struct DataWrapperByValue {
Data data_;
DataWrapperByValue(Data data) : data_(std::move(data)) { }
};
struct DataWrapperByMoveOrCopy {
Data data_;
template<typename T,
typename = typename std::enable_if<
std::is_same<typename std::decay<T>::type, Data>::value
>::type
>
DataWrapperByMoveOrCopy(T&& data) : data_(std::forward<T>(data)) { }
};
struct Foo {
Foo() { std::cout << " constructor\n";}
Foo(const Foo& data) { std::cout << " copy constructor\n";}
Foo(Foo&& data) { std::cout << " move constructor\n";}
};
struct Bar {
Bar() { std::cout << " constructor\n";}
Bar(const Bar& data) { std::cout << " copy constructor\n";}
Bar(Bar&& data) { std::cout << " move constructor\n";}
};
struct Baz {
Baz() { std::cout << " constructor\n";}
Baz(const Baz& data) { std::cout << " copy constructor\n";}
Baz(Baz&& data) { std::cout << " move constructor\n";}
};
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) } { }
};
Data function_returning_data() {
return Data();
}
int main() {
std::cout << "1. DataWrapperWithMove:\n";
Data d1;
DataWrapperWithMove a1(std::move(d1));
std::cout << "2. DataWrapperByValue:\n";
Data d2;
DataWrapperByValue a2(std::move(d2));
std::cout << "3. DataWrapperByMoveOrCopy:\n";
Data d3;
DataWrapperByMoveOrCopy a3(std::move(d3));
std::cout << "4. DataWrapperByMoveOrCopy with l-value:\n";
Data d4;
DataWrapperByMoveOrCopy a4(d4);
std::cout << "5. RVO:\n";
DataWrapperByValue a5(function_returning_data());
std::cout << "6. CompositeWrapperByMoveOrCopy with l-value:\n";
Data d6;
Foo f;
Bar b;
Baz z;
int i;
CompositeWrapperByMoveOrCopy a6(d6, std::move(f), b, std::move(z)); //works
//CompositeWrapperByMoveOrCopy a7(d6, std::move(f), z, std::move(b)); //SFINAE kills it
//CompositeWrapperByMoveOrCopy a8(d6, std::move(f), b, i); //SFINAE kills it
}