#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;
}