Boost logo

Boost :

Subject: Re: [boost] [result_of] Allow result_of to work with C++11 lambdas
From: Daniel Walker (daniel.j.walker_at_[hidden])
Date: 2013-04-21 21:53:02


On Apr 21, 2013, at 8:50 PM, "Jeffrey Lee Hellrung, Jr." <jeffrey.hellrung_at_[hidden]> wrote:

> On Sun, Apr 21, 2013 at 7:48 AM, Daniel Walker <daniel.j.walker_at_[hidden]>wrote:
>
>>
>> On Apr 21, 2013, at 3:04 AM, "Vicente J. Botet Escriba" <
>> vicente.botet_at_[hidden]> wrote:
>>> Do we know of some regression cases?
>>
>> It's not a matter of regressions but user expectations. boost::result_of's
>> documentation has said for a long time now that if decltype is not used
>> then TR1 is. It doesn't seem like a good idea to me to introduce a new
>> default scenario, a hybrid, which is a little hard to explain.
>
>
> Fair enough, but I don't think the fact that it's difficult to explain
> should, in and of itself, preclude its introduction.
>
>
>> Everything is easier if there is one switch between two standards for the
>> default behavior, namely, support for N3276.
>>
>
> Well, not universally. Those who want result_of to work with C++11 lambda's
> on compilers which do no support N3276 will find this new default scenario
> easier, I imagine.

If we release the hybrid mode not as the default but as a third option, and we hear user feedback such as "Hybrid mode is great. I'm surprised it isn't the default," then I might advocate making it the default. Of course, we'd need to roll it out over several releases due to the potential for regressions. The first would announce the pending breaking change and then a release or to later we could release the change. In the meantime, though, I think it is best to release it as a third option that people can get their hands on right away, and then we can see how user expectations change.

>
> However, there will also be regressions, i.e. valid user code that will no
>> longer compile if we change the default. An obvious one is user code that
>> is conditioned on the current two modes. If we change the default to a new
>> third mode, then such code will suddenly fail to compile in the default
>> case. For example:
>>
>> struct functor {
>> template<class T>
>> T operator()(T);
>> };
>>
>> template<class T>
>> struct S {
>> #ifdef BOOST_RESULT_OF_USE_DECLTYPE
>> typedef boost::result_of<functor(T)>::type type;
>> #endif
>>
>> #ifdef BOOST_RESULT_OF_USE_TR1
>> struct TR1functor {
>> template <class> struct result;
>> template<class F, class U>
>> struct result<F(U)> {
>> typedef T type;
>> };
>>
>> template<class U>
>> U operator()(U);
>> };
>>
>> typedef typename boost::result_of<TR1functor(T)>::type type;
>> #endif
>> };
>>
>> typedef S<int>::type type; // error if the default changes
>>
>
> Is this excised from actual code or a purely contrived example? Is it
> documented that we guarantee that defined( USE_DECLTYPE ) ^ defined(
> USE_TR1 ) ? If so, this seems like a brittle and overspecified guarantee to
> begin with. Anyways, at worst, can't we just define USE_TR1 for the hybrid
> result_of anyway?
>

I would characterize this as a plausible example, but either way it demonstrates currently valid code that will break if we change the default.

> There will be more subtle errors as well. The following will compile by
>> default on compilers with insufficient decltype support, since TR1 is used
>> by default, but it will fail if we change the default to the hybrid mode.
>>
>> struct functor {
>> int operator()();
>> };
>>
>> BOOST_STATIC_ASSERT((
>> boost::is_same<boost::result_of<functor()>::type, void>::value
>> ));
>>
>> This is due to a dark corner of TR1: the result and result_type members
>> are consulted in non-nullary functors but nullary functors always generate
>> void. (See the section on known difference between boost::result_of and TR1
>> in the documentation.)
>>
>
> The rationale for this always confused me, with the end result (it seems)
> that it makes TR1 result_of basically unusable for nullary function calls.
> In any case, again, at worst, we can retain this (dare I say,
> questionable?) behavior for nullary function calls for hybrid result_of.
>

The nullary function case is a big hole in TR1 and a strong motivation for the use of decltype, IMHO. But you cannot retain this behavior in the hybrid; since TR1 does not require result/result_type members in nullary functors (in order to compile), so they look the same as c++11 functors. So, again this is currently valid code that will break if you change the default. There are potentially other little issues like this, which is one of the reasons we've been so slow and cautious in migrating to decltype as the default.

- Daniel


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