как сделать std :: functions и lambdas, которые могут принимать аргументы любого типа - PullRequest
0 голосов
/ 22 сентября 2018

Я максимально упростил это, и я надеюсь, это будет ясно.У меня есть класс с именем Foo, который содержит член std :: function, который связан с функцией, которую я хочу вызвать.

Когда вызывается Foo::DoCallback, выполняется функция, которая является привязкой или назначена.Чтобы поддерживать различные типы параметров, я создал 2 конструктора и конструктор по умолчанию, который не принимает параметров

конструктор, который принимает std :: function с параметром типа int.
Foo(std::function<void(int)> callback, int a)

конструктор, который принимает std :: function, который принимает параметр bool.

Foo(std::function<void(bool)> callback, bool condition)

и конструктор по умолчанию, который не принимает никаких параметров ввсе.

Foo(std::function<void()> callback = nullptr) : Callback(callback)

в основном у меня 3 лямбды.каждая лямбда принимает параметры различного типа и передает их в качестве аргумента функции, которая будет использоваться в качестве обратного вызова.

  auto lambdaA = [](int a)
  {
    FunctionA(a);
  };

  auto lambdaB = [](bool condition)
  {
    FunctionB(condition);
  };

  auto lambdaC = []()
  {
    FunctionC();
  };

Проблема заключается в том, что всякий раз, когда мне нужен новый обратный вызов с различными типами аргументовЯ должен продолжать создавать;

  • лямбда, который должен быть передан в качестве аргумента при создании уникального poo Foo.
  • конструктор foo, который принимает новый тип std:: параметр функции, который принимает дополнительные типы параметров.


Есть ли способ сделать это проще?

вот полный код

--основная -

#include <iostream>
#include <string>
#include <memory>
#include "Foo.h"
void FunctionA(int a)
{
  std::cout << "FunctionA called. param 1 = " << std::to_string(a) << "\n";
}

void FunctionB(bool condition)
{
  std::cout << "FunctionB called. param 1 = " << std::to_string(condition) << "\n";
}

void FunctionC()
{
  std::cout << "FunctionC called with no params" << "\n";
}
int main()
{
  auto lambdaA = [](int a)
  {
    FunctionA(a);
  };

  auto lambdaB = [](bool condition)
  {
    FunctionB(condition);
  };

  auto lambdaC = []()
  {
    FunctionC();
  };

  std::unique_ptr<Foo> FooPtrA = std::make_unique<Foo>(lambdaA,10);
  std::unique_ptr<Foo> FooPtrB = std::make_unique<Foo>(lambdaB ,false);
  std::unique_ptr<Foo> FooPtrC = std::make_unique<Foo>(lambdaC);

  FooPtrA->DoCallback();
  FooPtrB->DoCallback();
  FooPtrC->DoCallback();

  return 0;
}

- Foo.h

#pragma once
#include <functional>
class Foo
{
public:
  //constructor with a parameter callback which could take an int parameter
  Foo(std::function<void(int)> callback, int a) 
  {
    Callback = std::bind(callback, a);
  }
  //constructor with a parameter callback which could take a bool parameter
  Foo(std::function<void(bool)> callback, bool condition)
  {
    Callback = std::bind(callback, condition);
  }

  //constructor with a parameter callback which takes no parameter
  Foo(std::function<void()> callback = nullptr) : Callback(callback)
  {
  }

  void DoCallback()
  {
    Callback(); //calling the callback function that is binded
  }
private:
  std::function<void()> Callback;
};

Ответы [ 2 ]

0 голосов
/ 22 сентября 2018

Продвинувшись на один шаг дальше, чем ответ Swordfish, вы можете устранить издержки std::function, параметризовав любой тип:

template<typename F, typename T>
Foo(F f, T a)
    : Callback{ std::bind(f, a) } } {}

Если вы хотите, чтобы это работало для произвольного числа аргументов, и вызовитеправильно двигать конструкторами:

template<typename F, typename... Args>
Foo(F&& f, Args&&... a)
    : Callback{ std::bind(std::forward<F>(f), std::forward<Args>(a)...) } {}
0 голосов
/ 22 сентября 2018

Использовать шаблон?

template<typename T>
Foo(std::function<void(T)> callback, T a) : Callback{ std::bind(callback, a); }
{}
...