C ++ std :: function не может найти правильную перегрузку - PullRequest
14 голосов
/ 08 ноября 2011

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

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

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

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

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

Ответы [ 3 ]

12 голосов
/ 08 ноября 2011

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

Framework:

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>
{};

EDIT
Теперь этот код поддерживает любой тип возврата.

1 голос
/ 08 ноября 2011

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

Set(std::function<void(int)>([](int a) {
    //...
}));
1 голос
/ 08 ноября 2011

Я предлагаю:

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

  void Set(void(*f)(int))
  { 
      std::function<void(int)> wrap(f);
      // ...
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...