|
Boost : |
From: Peter Dimov (pdimov_at_[hidden])
Date: 2008-04-05 18:00:08
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.
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk