Подтвердить что ты не робот

С++ std:: function не может найти правильную перегрузку

Рассмотрим следующий случай:

void Set(const std::function<void(int)> &fn);
void Set(const std::function<void(int, int)> &fn);

Теперь вызов функции с помощью

Set([](int a) {
    //...
});

Предоставляет ошибку "неоднозначный вызов перегруженной функции". Я использую Visual Studio 2010. Есть ли работа или другой метод для достижения чего-то подобного. Я не могу использовать шаблоны , потому что эти функции хранятся для дальнейшего использования, потому что я не могу определить количество параметров в этом случае. Если вы спросите, я могу представить более подробную информацию.

4b9b3361

Ответ 1

Я бы предложил это решение. Он должен работать с лямбдами, а также с функциями-объектами. Он может быть расширен, чтобы заставить его работать и с указателем функции (просто перейдите по ссылке внизу)

Структура:

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
    enum { arity = sizeof...(Args) };
};

template<typename Functor, size_t NArgs>
struct count_arg : std::enable_if<function_traits<Functor>::arity==NArgs, int>
{};

Использование:

template<typename Functor>
typename count_arg<Functor, 1>::type Set(Functor f) 
{
    std::function<void(int)> fn = f;
    std::cout << "f with one argument" << std::endl;
}

template<typename Functor>
typename count_arg<Functor, 2>::type Set(Functor f)
{
    std::function<void(int, int)> fn = f;
    std::cout << "f with two arguments" << std::endl;
}

int main() {
        Set([](int a){});
        Set([](int a, int b){});
        return 0;
}

Вывод:

f with one argument
f with two arguments

Я принял некоторую помощь от принятого ответа этой темы:


Работа с Visual Studio 2010

Так как Microsoft Visual Studio 2010 не поддерживает вариационные шаблоны, то фрейм-часть может быть реализована как:

template <typename T>
struct function_traits : public function_traits<decltype(&T::operator())>
{};

template <typename C, typename R, typename T0>
struct function_traits<R(C::*)(T0) const> { enum { arity = 1 }; };

template <typename C, typename R, typename T0, typename T1>
struct function_traits<R(C::*)(T0,T1) const> { enum { arity = 2 }; };

template <typename C, typename R, typename T0, typename T1, typename T2>
struct function_traits<R(C::*)(T0,T1,T2) const> { enum { arity = 3 }; };

//this is same as before 
template<typename Functor, size_t NArgs, typename ReturnType=void>
struct count_arg : std::enable_if<function_traits<Functor>::arity==NArgs, ReturnType>
{};

ИЗМЕНИТЬ
Теперь этот код поддерживает любой возвращаемый тип.

Ответ 2

Я предлагаю:

  void Set(void(*f)(int, int))
  { 
      std::function<void(int,int)> wrap(f);
      // ...
  }

  void Set(void(*f)(int))
  { 
      std::function<void(int)> wrap(f);
      // ...
  }

Ответ 3

Вы можете вручную указать тип:

Set(std::function<void(int)>([](int a) {
    //...
}));