Выражение SFINAE это очень удобный способ написать несколько альтернативных функций для выполнения одной и той же задачи и выбрать лучшую, которая компилируется. Вы упоминаете критические выражения в прототипе функции, и если они недействительны, прототип игнорируется, и мы надеемся, что будет выбрано другое.
Это очень удобно, за исключением объявления прототипа для случая, когда выражение не определено. Обычно набор прототипов должен быть разделен на взаимоисключающие домены, так как они могут быть равны с точки зрения разрешения перегрузки, и включение двух в набор перегрузки вызовет неоднозначность.
Всегда можно определить старомодный тип черты для данного выражения, для использования с 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 {};
Если бы не необходимость чего-то извлекать из false_type
, std::conditional
может перейти непосредственно к прототипу функции, и весь этот шаблон исчезнет.
Есть ли альтернатива? Может быть, какой-то способ уменьшить ранг перегрузки функции, который не мешает выводу типа?
Одной из альтернатив является добавление функции диспетчера, которая добавляет фиктивный параметр, такой как тег, для комнаты маневра, чтобы сделать списки аргументов различными.
// "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 ... ) );
}
Других решений пока нет …