Boost logo

Boost :

Subject: Re: [boost] [result_of] now uses decltype on release branch
From: Joel de Guzman (djowel_at_[hidden])
Date: 2012-09-05 02:54:34


On 9/5/2012 1:46 PM, Daniel Walker wrote:
> On Sep 4, 2012, at 10:29 PM, Joel de Guzman wrote:
>
>> On 9/5/2012 10:08 AM, Daniel Walker wrote:
>>> On Sep 4, 2012, at 8:01 PM, Joel de Guzman wrote:
>>>
>>>> On 9/5/2012 12:53 AM, Michel Morin wrote:
>>>>
>>>>> Joel de Guzman wrote:
>>>>>> However! This makes the current result_of code not an exact replacement
>>>>>> to decltype which allows this variation of above:
>>>>>
>>>>> Right. boost/std::result_of is not an exact replacement to decltype,
>>>>> since decltype allows SFINAE but boost/std::result_of doesn't.
>>>>>
>>>>> [...]
>>>>>> If Fusion's invoke used decltype instead of
>>>>>> result_of, it would have worked.
>>>>>
>>>>> I tried to compile my test case for fusion::invoke with SFINAE-enabled
>>>>> result_of, but it failed to compile. After adding a "fallback type" to
>>>>> SFINAE-enabled result_of, then the test case runs fine.
>>>>
>>>> The following code (attached) demonstrates the problem of
>>>> Fusion::invoke with the current decltype based result_of. Comment
>>>> out the first line for the code to use plain decltype vs. result_of.
>>>> Notice that because result_of does not allow SFINAE, it barfs when
>>>> the compiler tries the first overload of invoke (substitution failure).
>>>> The compiler could have chosen the second overload.
>>>>
>>>> I see no other way to get around this problem of result_of. I am
>>>> getting inclined to use decltype directly in fusion instead of
>>>> going through result_of. Problems like this kinda defeats the
>>>> purpose of decltype-ifying result_of, but heck.
>>>>
>>>> The question is: should we allow SFINAE for result_of. I think now
>>>> that we should.
>>>
>>> Thanks for the sample code, Joel. I don't exactly understand the problem though. Why
>> overload invoke? Isn't this the perfect occasion to use rvalue references? invoke could be
>> defined as follows and everything would work fine.
>>>
>>> template <typename F, typename Arg>
>>> typename boost::result_of<F(Arg&&)>::type
>>> invoke(F f, Arg&& arg)
>>> {
>>> return f(boost::forward<Arg>(arg));
>>> }
>>>
>>> The decltype-based result_of constructs the call-expression using rvalue-references
>>> (via
>> boost::decval) for perfect forwarding.
>>
>> Yes, I agree. This is the perfect occasion to use rvalue references.
>> What you wrote is a plausible solution and one I am looking into
>> right now (not as simple as the test code though).
>>
>> However... that is pretty much besides the point. And the point is that
>> the current decltype based result_of breaks with overloads.
>>
>
> OK, I think there's something we can do about this. I've attached a modification of
> your
sample code that uses a simple is_callable metafunction predicate with enable_if so that
SFINAE can kick in. It's a proof of concept. I'm not familiar with Eric's can_be_called so
I don't know if these metafunctions test exactly the same thing. My is_callable tests if a
valid call expression can be constructed from a result_of-style signature; i.e. can the
signature be used with result_of to get a result type.
>
> Now, this could be folded into result_of; e.g. result_of could inherit from
enable_if_lazy<is_callable<...>, ...>, or something like that, if you follow me. Is it
worth fleshing this out? Or should we just leave it as a known (and soon to be documented)
difference in behavior between TR1 and decltype-based result_of?

I'm not sure. To me, I think it's easier to simply avoid result_of on
C++11 and just use decltype directly. Problem solved. Why use an
inferior tool when something better is available anyway?

Regards,

-- 
Joel de Guzman
http://www.boostpro.com
http://boost-spirit.com

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