Устранить неоднозначность перегрузки с помощью 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).

Другие вопросы по тегам