Idiomatic reserves in the expression sfinae

Expression SFINAE is a very convenient way to write multiple alternative functions to do the same and choose the best one that compiles. You specify critical expression (s) in the function prototype and if they are not valid, the prototype is ignored and hopefully another one will be chosen.

This is very convenient, except for declaring a prototype for the case when the expression is undefined. Typically, the prototype set should be split into mutually exclusive domains, since they can be equal in terms of overload resolution and allow two in the overload set to cause ambiguity.

It is always possible to define an old fashioned trait type for a given expression, for use with std::enable_if

:

template< typename s, typename t, typename u, typename = void >
struct is_product_serializable : std::false_type {};

template< typename s, typename t, typename u >
struct is_product_serializable< s, t, u, typename std::conditional< true, void,
   decltype( std::declval< s >() << std::declval< t >() * std::declval< u >() )
>::type >
    : std::true_type {};

      

If there was no need to get something from false_type

, I std::conditional

could go directly to the function prototype, and this whole boilerplate plan would disappear.

Is there any alternative? Perhaps somehow reduce the rank of function overloading that doesn't interfere with type deduction?

+3


source to share


1 answer


One option is to add a dispatcher function that adds a dummy parameter, such as a tag, for the maneuver room to make the argument list different.



// "Primary" template is just a dispatcher
template< typename ... args >
void chuck( args && ... rem ) {
    return chuck_impl( 0, std::forward< args >( a ) ... );
}

// preferred alternative matches int to 0 but is controlled by SFINAE
template< typename t, typename u, typename ... args >
auto chuck_impl( int, t && a, u && b, args && ... rem )
-> typename std::conditional< true, void, decltype( blah( a, rem ... ) * b ) >::type {
    blah( a, rem ... ) * b;
}

// fallback requires int => float conversion
template< typename t, typename u, typename ... args >
void chuck_impl( float, t && a, u && b, args && ... rem ) {
    bleh( a + chuck_impl( b, rem ... ) );
}

      

0


source







All Articles