Boost logo

Boost :

Subject: Re: [boost] How to detect if f() returns void or not?
From: Andy Venikov (avenikov_at_[hidden])
Date: 2009-12-17 15:16:16


Eric Niebler wrote:
> Andy Venikov wrote:
>> Eric Niebler wrote:
>>>
>>> http://www.boost.org/doc/libs/1_41_0/doc/html/proto/appendices.html#boost_proto.appendices.implementation.function_arity
>>
>>
>>
>> I gotta admit, this thing is amazing. I actually needed to implement a
>> way to tell whether a type is an io manipulator (basically telling if
>> calling T(ostream) is a well-formed expression), and was at a loss. I
>> was about to post a question on comp.lang.c++ but suddenly came across
>> this thread and your solution fit like hand in glove.
>
> Great. Maybe this technique deserves to be more widely known.
>
>> I do have a question though.
>> In your "fununwrap2" class you define the typedef as
>>
>> typedef private_type const &(*pointer_to_function)
>> (dont_care, dont_care);
>>
>> and dont_care constructor has ellipsis instead of an argument list.
>>
>> Why use dont_care at all? Why not define the pointer_to_function type as:
>>
>> typedef private_type (*pointer_to_function)
>> (...);
>>
>> It seems to be working just as good.
>> Or am I missing something?
>
> I think it's me that missing something. The goal is to come up with the
> worst possible conversion sequence so that our overload gets picked only
> if there really is no other option. My thought was that using dont_care
> makes the conversion sequence longer because not only does it involve an
> ellipsis conversion, but it also involves a user-defined conversion (to
> dont_care). But to my surprise, that seems not to be the case.
>
> Consider this:
>
> struct dont_care {dont_care(...) {}};
>
> char fun(dont_care) { return 0; }
> int fun(...) { return 0; }
>
> int main()
> {
> fun(1);
> typedef char assert_[1==sizeof(fun(1))];
> }
>
> For some reason, the overload that involves both an ellipsis conversion
> *and* a user-defined conversion is actually preferred over the one that
> involves just an ellipsis conversion. I don't understand that, but it
> wouldn't be the first time that I was baffled by the C++ overloading rules.
>
> Sometimes I think I'll never really know C++.

Is it just me or are the overload resolution rules in the standard are
phrased in language really difficult to understand?
I've been trying to find the answer to the ellipsis thing and, by my
word, I can't understand what the rules say even after reading them
several times.

Anyway, Eric, I had a question regarding your technique. It looks like
the technique is not going to work with functors that have templated
operator() In this case the template will happily eat arguments of any
type, even the ones that it's not supposed to be called with. The error
will not be detected during instantiation of can_be_called<> but when
the functor is actually called. So, for example,

template <typename Fun, typename Arg1, typename Arg2>
bool CanBeCalled(Fun const &, Arg1 const &, Arg2 const &)
{
   return can_be_called<Fun, Arg1, Arg2>::result;
}

CanBeCalled(bind(main, _1, _2), string(), complex());

Will produce "true".

But this:
bind(main, _1, _2)(string(), complex());

Will generate a compile-time error.

Do you have any other tricks up your sleeve to solve it?

Thanks,
     Andy.


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