Boost logo

Boost :

Subject: Re: [boost] [result_of] Usage guidelines
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2012-09-08 11:34:09


On Sep 8, 2012, at 9:59 AM, Andrey Semashev wrote:

> On Tuesday 04 September 2012 11:07:39 you wrote:
>>
>> Jeffrey have suggested a good solution in his reply. I think it can be
>> described in the result_of docs to resolve the confusion in the future. I
>> can update the docs if noone objects.
>
> I've added a clarification note to the result_of docs in trunk. Here is the
> added section:
>

Thanks for the suggestion Andrey. Using remove_cv is a good tip, and I think it would be useful to have a tips and/or cookbook section. But a change like this should really be discussed on the list before committing to trunk. I've reverted your change, since discussion is still underway. I just wouldn't want something like this to accidentally slip into a release without being reviewed. My specific concern is that your tip is more appropriate for an advanced user than a complete novice, and I wouldn't want to confuse or misled the novice.

This thread has been interesting and I've enjoyed following it. There have been several good comments that I think can be compiled in a convenient way for users and placed in the docs.

> <quote>
> The result template must be specialized for every valid calling signature of
> the function object.

The rest of your example seems reasonable, but this sentence is not entirely true. The result template is not required at all in C++11; it is only needed for C++03 and for portability to compilers lacking sufficient decltype support. Even on C++03 the result template is only needed when the return type varies between overloads. If the return type is constant, you can skip the whole hassle and just define result_type. I wouldn't want a novice to read that sentence and then start spending time specializing the result template when he or she never actually need it.

Here's a rough outline of what I think is important for the guidelines to convey.

1) If you are targeting C++11 and are not concerned about portability to non-compliant compilers or previous versions of the standard, then use std::result_of.

2) If you are targeting C++11 but may port your code to legacy compilers sometime in the future, use boost::result_of with decltype.

3) If compiler portability is required, use boost::result_of with the TR1 protocol.

The point I'm trying to emphasis is that users only need to incur the expense of the TR1 protocol when they want the benefit of portability.

> If the operator() accepts arguments by (possibly const)
> reference and/or is const qualified, the result specialization must take this
> into account. Type traits and more generic specializations may help to reduce
> the number of result specializations. This way result_of users will be able to
> specify argument types exactly according to the function object call
> expression. For example:
>
> struct functor {
> template<class> struct result;
>
> // Use template parameter F to match the function object. This will
> allow result deduction for both const and non-const functor.
> template<class F, class T>
> struct result<F(T)> {
> // When argument type is matched like above, remember that the
> type may be a (const-qualified) reference.
> // Use type traits to transform the argument type.
> typedef typename remove_cv<typename
> remove_reference<T>::type>::type argument_type;
> typedef argument_type type;
> };
>
> // The operator can be called on both const and non-const functor. The
> argument can be lvalue or rvalue.
> template<class T>
> T operator()(T const& x) const
> {
> return x;
> }
> };
>

This is a good example.

> // All following result_of uses are valid and result in int
> typedef boost::result_of< functor(int) >::type type1; // the argument is
> rvalue
> functor f;
> type1 r1 = f(10);
>
> typedef boost::result_of< const functor(int) >::type type2; // the
> function object is const
> const functor cf;
> type2 r2 = cf(10);
>
> typedef boost::result_of< functor(int&) >::type type3; // the argument is
> lvalue
> int a = 10;
> type3 r3 = f(a);
>
> typedef boost::result_of< functor(int const&) >::type type4; // the
> argument is const lvalue
> const int ca = 10;
> type4 r4 = f(ca);
> </quote>
>

I'm not sure that including verbose, repetitive client code clarifies anything. It might be better to just demonstrate the result template usage.

- Daniel


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk