#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <iostream>
#include <vector>
#include <utility>
#include <tuple>
#include <cxxabi.h>
auto demangle = [](const char* str) -> const char*
{
static int sta;
return abi::__cxa_demangle(str, 0, 0, &sta);
};
struct disp {
::std::ostream& os;
disp(::std::ostream& os):os(os){}
template<typename T>
::std::ostream& operator()(T& x) const
{ return os << x << " "; }
};
struct Bar
{
Bar():s(""){ ::std::cout << "default constructor" << ::std::endl; }
Bar(Bar&& arg):s(std::move(arg.s)){ ::std::cout << "move constructor of " << s << ::std::endl; }
Bar(Bar const&arg):s(arg.s){ ::std::cout << "copy constructor of " << s << ::std::endl; }
Bar(std::string str):s(str){ ::std::cout << "initialize " << s << ::std::endl; }
::std::string s;
};
template<typename...Args>
struct Foo
{
Foo(Args&&... args)
: t_(std::forward<Args>(args)...)
{ }
// ref確認用
void change()
{
boost::fusion::for_each(t_, [](Bar& b){ b.s += std::string("_"); });
}
std::tuple<Args...> t_;
};
// lvalue refならlvelue refのまま扱う
template<typename...Args>
auto foo(Args&... args)
-> Foo<Args&...>
{
return Foo<Args&...>{args...};
}
// rvalue refならmoveする
template<typename...Args>
auto foo(Args&&... args)
-> Foo<Args...>
{
return Foo<Args...>{std::forward<Args>(args)...};
}
::std::ostream& operator<<(::std::ostream& os, Bar const& bar)
{
return os << bar.s;
}
template<typename...Args>
::std::ostream& operator<<(::std::ostream& os, Foo<Args...> const& foo)
{
boost::fusion::for_each(foo.t_, disp(os));
return os;
}
int main(int, char*[])
{
Bar bl("lvalue"), bx("xvalue");
auto f = foo(bl, std::move(bx), Bar("prvalue"));
// lvelueは参照のまま,rvalueはどちらもキャプチャしてある
::std::cout << demangle(typeid(f).name()) << ::std::endl;
::std::cout << f << ::std::endl;
// 挙動確認
f.change();
::std::cout << f << ::std::endl;
::std::cout << bl << ::std::endl;
// constも
Bar const bcl("lvalue"), bcx("xvalue");
auto fc = foo(bcl, std::move(bcx));
::std::cout << demangle(typeid(fc).name()) << ::std::endl;
::std::cout << fc << ::std::endl;
return 0;
}