Устранить неоднозначность перегрузки с помощью SFINAE
Я обнаружил похожие случаи, но они обычно заканчивали тем, что я (думаю) делаю здесь.
Я хочу иметь возможность вызывать функцию с одним или несколькими параметрами, очевидно, если функция существует с перегрузками с несколькими параметрами, правильная версия не может быть выведена без помощи.
Поскольку я также указываю количество аргументов, я решил, что этой информации будет достаточно для компилятора, чтобы определить правильную перегрузку. Кажется, это не так, и я надеюсь, что вы сможете показать мне, почему.
код: http://coliru.stacked-crooked.com/a/5e6fd8d5418eee3c
#include <iostream>
#include <type_traits>
#include <functional>
template < typename R, typename... A, typename... Args >
typename std::enable_if< sizeof...( A ) == sizeof...( Args ), R >::type
call_my_function( R(*func)(A...), Args ...a )
{
return func( a... );
}
int arg_count() { return 0; }
int arg_count(int) { return 1; }
int arg_count(int,int) { return 2; }
int main()
{
std::cout << call_my_function( arg_count, 0 ) << std::endl;
return 0;
}
Короче говоря, я попытался, чтобы все функции, у которых количество аргументов отличалось от количества предоставленных мной аргументов, не выполнялись с помощью SFINAE. Но, похоже, их все равно считают и двусмысленность остается.
1 ответ
К сожалению нет; SFINAE можно использовать для выбора между различными определениями шаблонов функций, но не между перегрузками функций, передаваемыми в качестве аргумента.
Это связано с тем, что перегруженная функция, переданная в качестве аргумента, должна быть преобразована в одну перегрузку, прежде чем будут вычислены зависимые типы в определении функции шаблона, и SFINAE начнет работать.
Вы можете увидеть это, создав n
перегруженные определения шаблонов, где n - 1
максимальное количество аргументов, которое вы хотите обработать:
template < typename R, typename... Args >
typename std::enable_if< 0 == sizeof...( Args ), R >::type
call_my_function( R(*func)(), Args ...a )
{
return func( a... );
}
template < typename R, typename A1, typename... Args >
typename std::enable_if< 1 == sizeof...( Args ), R >::type
call_my_function( R(*func)(A1), Args ...a )
{
return func( a... );
}
template < typename R, typename A1, typename A2, typename... Args >
typename std::enable_if< 2 == sizeof...( Args ), R >::type
call_my_function( R(*func)(A1, A2), Args ...a )
{
return func( a... );
}
Здесь каждый arg_count
решает ровно один call_my_function
определение, поэтому нет никакой двусмысленности в конкретном call_my_function
определение, к которому arg_count
Сдан.
Возможным решением будет генерировать эти n
перегружает либо вручную, либо используя препроцессор (например, используя Boost.Preprocessor).