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?


Joel de Guzman

Boost list run by bdawes at, gregod at, cpdaniel at, john at