Boost logo

Boost :

Subject: Re: [boost] [TypeTraits] propose new callable-type call traits
From: Hui Li (hui.li_at_[hidden])
Date: 2014-01-11 19:21:42


Sorry I wasn't very clear in my last email. I want to add that if i only had has_call, and implemented my make_the_call like in the following, it would be very very wrong.

template < typename E, typename T > // T is some user-defined class outside the library
typename std::enable_if<
   has_call<T(E)>::value
>::type
make_the_call(const E& e, T& t)
{
        t(e); // if the call is ambiguous, the user must, and will, get a compiler error here
               // and since has_call disable of this overload and enables the next one (see below)
               // we turn an ambiguity error into a mere no-call, which is very very wrong
}

// default no-call behavior, which would be called if T(E) is actually ambiguous
template < typename E, typename T >
typename std::enable_if<
   not has_call<T(E)>::value
>::type
make_the_call(const E& e, T& t)
{
   // do nothing
}

On Jan 11, 2014, at 6:55 PM, Hui Li <hui.li_at_[hidden]> wrote:

>
> On Jan 11, 2014, at 2:55 PM, TONGARI J <tongari95_at_[hidden]> wrote:
>
>> Hi,
>>
>> 2014/1/12 Hui Li <hui.li_at_[hidden]>
>>
>>> I've implemented a few traits classes (code attached below) that, for a
>>> given callable-type T, and a set of Args..., detects whether the function
>>> call T::operator()(Args...) would be
>>> (1) valid,
>>> (2) ambiguous, or
>>> (3) none is viable.
>>> where T is allowed to have arbitrary overloaded operator()'s.
>>>
>>> This could be useful for programmers who want to
>>> (1) make the function call only when it's valid,
>>> (2) generate customized error/warning messages when it's ambiguous, or
>>> handle/redirect it without getting an ambiguous compiler error, and
>>> (3) redirect non-viable calls to some default behavior, which can be
>>> different than how it's handled when the call is ambiguous.
>>>
>>> If people are interested, I suppose this could be a useful addition to
>>> TypeTraits.
>>> I would appreciate any feedback!
>>>
>>> For clarity, the implementation and demonstration attached below is
>>> written in c++11. It can be easily ported to c++98/03 compilers by using
>>> TypeTratis to replace the std type traits, BOOST_TYPEOF_KEYWORD to replace
>>> decltype, and Boost.Preprocessor to generate code for arbitrary arity.
>>>
>>
>> It's interesting that you use ambiguity to distinguish the types.
>> Anyway, your code doesn't support function(pointer) which is also Callable,
>> and... are you sure your approach can be ported back to C++03 where there's
>> no SFINAE on expression?
>
> SFINAE on expression is not important in my approach. Since the has_compatible_callback merely uses has_valid_call, and my has_valid_call does the same thing as your has_call (besides the return type), i'm quite certain we can use your has_call for it's implementation and should be able to port to whatever compiler that works with your has_call.
>
>>
>> FWIW, I have my has_call implementation:
>> https://github.com/jamboree/boost.has_call
>> which works for both C++11/03.
>
> Very interesting, I will look into it, and see if i can switch to your has_call so that mine works on gcc4.3 (which I'm guessing is one of the compilers that don't support SFINAE on expression?)
>
>> I have real world usage of has_call (or has_valid_call in yours), but I
>> don't have the need of has_ambiguous_call so far.
>
> I have real world use for has_compatible_call, because has_call was insufficient in detecting ambiguous callback overloads provided by user defined classes (out of my control since I'm writing a library), in which case I want to generate a compiler error rather than using some default handler.
>
> For example,
>
> // in my real world application, there are other make_the_call overloads that make it more interesting than in this demonstration
>
> template < typename E, typename T > // T is some user-defined class outside the library
> typename std::enable_if<
> has_valid_call<T(E)>::value or has_ambiguous_call<T(E)>::value
>> ::type
> make_the_call(const E& e, T& t)
> {
> t(e); // if the call is ambiguous, the user must, and will, get a compiler error here
> // if we had used just has_valid_call in the enable_if, it would turn an erroneous ambiguity into a no-call
> // which would be very very wrong
> }
>
> // default no-op behavior
> template < typename E, typename T >
> typename std::enable_if<
> has_no_viable_call<T(E)>::value
>> ::type
> make_the_call(const E& e, T& t)
> {
> // do nothing
> }
>
>
>>
>> _______________________________________________
>> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
>
>
> _______________________________________________
> Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


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