
Eric Niebler:
I clearly should have fleshed this out a bit more. Consider something like a fusion::make_tuple function object
struct make_tuple { template<typename Sig> struct result;
template<typename This, typename Arg> struct result< This( Arg ) > { typedef tuple< Arg > type; };
// This is wrong! template<typename Arg> typename result< make_tuple( Arg const & ) >::type operator ()( Arg const &arg ) { return tuple< Arg const & >( arg ); } };
This is wrong because make_tuple(1) will cause the resulting tuple to hold on to a dangling reference. But had it been called as:
int const i = 0; make_tuple( i );
... then it's correct.
Yes. It's also wrong because result_of<make_tuple(int&)>::type says tuple<int&>, but the result of make_tuple( i ) is actually tuple<int const&>. But this is not a problem with result_of. It's not supposed to be used in this self-referential way. result_of<F(X)>::type is nothing more than an alias of decltype(f(x)), where f and x have types F and X, respectively. So if you have: return f(x); you can write template<class X> typename result_of<F(X const&)>::type g( X const & x ) { return f(x); } You don't use result_of<G(X)> in the return type of g(x). This would be the equivalent of using decltype(g(x)) as the return type of g. If you write the actual make_tuple: struct make_tuple { template<class X> tuple<X> operator()( X const & x ) const { return tuple<X>( x ); } template<class X> tuple<X&> operator()( reference_wrapper<X> const & x ) const { return tuple<X&>( x.get() ); } }; you'll see that it's relatively easy to write a result_of specialization for it. The references are an annoyance, sure. But the idea is that you start with the function object and then derive its result_of, not vice versa. Maybe I'm missing something else.