
[The following expresses the guidelines I've been using, which may or may not be the official Boost.ResultOf guidelines. But they make the most sense to me.] On Mon, Sep 3, 2012 at 12:08 AM, Andrey Semashev <andrey.semashev@gmail.com>wrote:
Hi,
I wonder what is the correct way of declaring polymorphic function object result types and how to use result_of template with regard to argument types. If a function object receives arguments by reference, should its member result<> template be specialized for reference types as well?
Not necessarily. I believe it is sufficient to sprinkle some remove_reference's and remove_const's around if the cv and reference qualifiers of the arguments don't matter. Also, should result_of<> for this function be instantiated
with reference argument types?
Depends if the arguments of the actual call expression you're interested in are lvalues or rvalues. struct my_foo
{ template< typename > struct result;
// Is this correct? template< typename ArgT > struct result< my_foo(ArgT) > { typedef ArgT type; };
No.
// Or is this correct? template< typename ArgT > struct result< my_foo(ArgT const&) > { typedef ArgT type; };
Not quite (based on your overload of operator() below). Use the former signature, with a "typedef typename remove_cv< typename remove_reference< ArgT >::type >::type". The latter composition of metafunctions occurs so frequently that I just use a remove_qualifiers that is equivalent to remove_cv< remove_reference<T>::type >::type.
template< typename ArgT > ArgT operator() (ArgT const& arg) const { return arg; } };
I realize that I can provide both result<> specializations and it will work either way. But when there are more than one argument the specializations begin to pile quickly. Consider also rvalue references and const and non-const qualified my_foo.
You typically only have to provide as many specializations of result<> (directly and indirectly) as you have overloads of operator(), and quite often fewer. A little metaprogramming regarding cv and reference qualifiers might be necessary, though :) Another question I have is how to use result_of<> when my_foo is
external (i.e. provided by a third party library)?
// Which one is the right way? typedef result_of< my_foo(int) >::type result_type1; typedef result_of< my_foo(int const&) >::type result_type2;
Again, depends on if you call it like int x = 0; my_foo(x); // result_of< my_foo( int & ) >::type or int const x = 0; my_foo(x); // result_of< my_foo( int const & ) >::type or my_foo(0); // result_of< my_foo( int ) >::type
I cannot know what result<> specializations are provided by my_foo, so probably there isn't an ultimate answer.
True; you hope result<> specializations are done carefully and thoughtfully :/
But perhaps there are some guidelines or best practices? I've looked at result_of docs but there are no recommendations on this.
Someone may chime in and refute my position on this :) - Jeff