
On Monday 03 September 2012 13:53:18 Jeffrey Lee Hellrung, Jr. wrote:
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.
[snip]
// 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.
Yes, this seem to simplify things a lot, thanks for the hint. It gives the correct result type for most cases except when argument type is a non-const lvalue reference. In this case incorrect result_of instantiations will also work, which may not be expected. I suppose, in such cases additional specializations are still needed: struct my_foo { template< typename > struct result; template< typename ArgT > struct result< my_foo(ArgT const&) >; template< typename ArgT > struct result< my_foo(ArgT&) > { typedef ArgT type; }; template< typename ArgT > ArgT operator() (ArgT& arg) const { return arg; } };
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
Ok, so the rule of thumb is to always instantiate result_of on the exact (reference) types of arguments you have and let the result<> specializations deal with references. Makes sense, thank you.