
Eric Niebler wrote:
Andy Venikov wrote:
Eric Niebler wrote:
http://www.boost.org/doc/libs/1_41_0/doc/html/proto/appendices.html#boost_pr...
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.