#include <iostream>
#include <vector>
#include <initializer_list>
struct Test {
std::string pString;
Test(){
std::cout << "construct" << std::endl;
}
Test(const std::string& aString):pString(aString){
std::cout << "construct(prepare)" << std::endl;
}
Test(std::nullptr_t){
std::cout << "construct(nullptr)" << std::endl;
}
Test& operator = (std::nullptr_t){
std::cout << "assign(nullptr)" << std::endl;
return *this;
}
Test(const Test& aTest){
std::cout << "construct(const self&)" << std::endl;
pString = aTest.pString;
}
Test& operator = (const Test& aTest){
std::cout << "assign(const self&)" << std::endl;
if(&aTest != this){
pString = aTest.pString;
}
return *this;
}
Test(Test&& aTest){
std::cout << "construct(self&&)" << std::endl;
std::swap(pString, aTest.pString);
}
Test& operator = (Test&& aTest){
std::cout << "assign(self&&)" << std::endl;
if(&aTest != this){
std::swap(pString, aTest.pString);
}
return *this;
}
~Test(){
std::cout << "destroy" << std::endl;
}
};
template <typename Output_t, typename ...Input_t>
inline Output_t& Compact(Output_t& aOutput, Input_t&& ...aInput){
// should I do this?
if(!sizeof...(aInput)){
return aOutput;
}
// I like typedefs as they shorten the code :)
typedef typename Output_t::value_type Type_t;
// can be either lvalues or rvalues in the initializer_list when it's populated.
std::initializer_list<Type_t> vInput = { std::forward<Input_t>(aInput)... };
// now move the initializer_list into the vector.
aOutput.reserve(aOutput.size() + vInput.size());
for(auto vIter(vInput.begin()), vEnd(vInput.end()); vIter != vEnd; ++vIter){
// move (don't copy) out the lvalue or rvalue out of the initializer_list.
aOutput.emplace_back(std::move(const_cast<Type_t&>(*vIter))); // <- THIS!
}
// done! :)
return aOutput;
}
int main() {
// assign the values to track both string and memory moves
Test vTestL("lvalue"), vTestR("rvalue");
// claim 1KB of memory so results are not affected by SSO (small string optimization)
vTestL.pString.reserve(1024);
vTestR.pString.reserve(1024);
std::cout << std::endl;
std::cout << "Input(before):" << std::endl;
std::cout << "LValue: " << vTestL.pString
<< " - 0x" << reinterpret_cast<const void*>(vTestL.pString.c_str())
<< " -- (should be unscathed)" << std::endl;
std::cout << "RValue: " << vTestR.pString
<< " - 0x" << reinterpret_cast<const void*>(vTestR.pString.c_str())
<< " -- (should be relocated)" << std::endl;
std::cout << std::endl;
std::vector<Test> vTests;
Compact(vTests, vTestL, std::move(vTestR));
std::cout << std::endl;
std::cout << "Input(after):" << std::endl;
std::cout << "LValue: " << vTestL.pString
<< " - 0x" << reinterpret_cast<const void*>(vTestL.pString.c_str())
<< " -- (should be unscathed)" << std::endl;
std::cout << "RValue: " << vTestR.pString
<< " - 0x" << reinterpret_cast<const void*>(vTestR.pString.c_str())
<< " -- (should be relocated)" << std::endl;
std::cout << std::endl;
std::cout << std::endl;
std::cout << "Output:" << std::endl;
std::cout << "LValue: " << vTests[0].pString
<< " - 0x" << reinterpret_cast<const void*>(vTests[0].pString.c_str())
<< " -- (should be unscathed)" << std::endl;
std::cout << "RValue: " << vTests[1].pString
<< " - 0x" << reinterpret_cast<const void*>(vTests[1].pString.c_str())
<< " -- (should be unscathed)" << std::endl;
std::cout << std::endl;
return 0;
}