samedi 22 septembre 2018

how to make std::functions and lambdas which could take any type of argument

I have simplified this as much as I can and hopefully, it will be clear. I have a class called Foo which contains an std::function member that is bind to a function that I want to call.

When Foo::DoCallback is called, the function that is a bind or assigned is executed. In order to support the different types of parameters, I have created 2 constructors and a default constructor that takes no parameter

a constructor that takes std::function with an int type parameter.
Foo(std::function<void(int)> callback, int a)

a constructor that takes std::function that takes a bool parameter.

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

and the default constructor that takes no parameters at all.

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

in the main, I have 3 lambdas. each lambda takes a different type of parameters and passes them as an argument to the function that would be used as a callback.

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

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

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

The problem is that, whenever I need a new callback with different types of argument, I have to keep creating;

  • a lambda that needs to be passed as an argument when creating the Foo unique ptr.
  • a foo constructor that takes the new type of std::function parameter that takes the additional types of parameter.


Is there a way to make this simpler?

here is the full code

--main--

#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>(FunctionA,10);
  std::unique_ptr<Foo> FooPtrB = std::make_unique<Foo>(FunctionB,false);
  std::unique_ptr<Foo> FooPtrC = std::make_unique<Foo>(FunctionC);

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

Aucun commentaire:

Enregistrer un commentaire