Boost logo

Boost :

Subject: Re: [boost] How to detect if f() returns void or not?
From: Eric Niebler (eric_at_[hidden])
Date: 2009-12-19 21:20:32


On 12/18/2009 9:16 AM, Andy Venikov wrote:
> Eric Niebler wrote:
>> 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.

You're not alone. Overload resolution is one of the most difficult areas
of C++. Makes templates look easy.

> 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".

As it should, IMO. bind() returns a function object that has an
operator() that accepts the specified arguments.

> But this:
> bind(main, _1, _2)(string(), complex());
>
> Will generate a compile-time error.

Yup. :-(

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

The only solution would be to modify the bind function object so that
its operator() refused to accept arguments that its bound function
doesn't also accept. This can be done with SFINAE using something akin
to can_be_called. I'm not suggesting that such a change be made to
Boost.Bind, but it would have one advantage: if users try to pass
unacceptable arguments, the resulting error would point to the offending
line in *their* code rather than someplace deep in Boost.Bind.

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

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