1

could you please help me how to handle (initialize, call) std::array of structs of std::function. Code like below:

class A
{
  struct Functions
  {
    std::function<bool()> handler1;
    std::function<bool()> handler2;
  };

  bool foo1();
  bool foo2();
  bool foo3();
  bool foo4();
  std::array<Functions, 2> Func_Arr;
};

I would like to map something like:

Func_Arr[0].hanlder1 = foo1;  
Func_Arr[0].hanlder2 = foo2;  
Func_Arr[1].hanlder1 = foo3;  
Func_Arr[1].hanlder2 = foo4;  

and then call only proper handler

I cannot figure out how to handle it, I mean how to mapp functions foo1 and foo2 to the struct and then call them via Func_Arr.

Tried to compile many times but failed

7
  • 3
    To call A::foo1, you need an instance of A. Commented Apr 18 at 13:31
  • You have two Functions elements in the array. Is A::foo1 supposed to call the Functions::foo1 method in both of them? Commented Apr 18 at 13:37
  • 1
    Looks like question suffers from XY problem. This is strange you have fooX. Commented Apr 18 at 13:46
  • 2
    Non-static member functions need an instance of the class to operate on. Either make your functions static, use std::function<bool(A*)>, or wrap them in lambdas that capture an instance of A. Commented Apr 18 at 13:46
  • 1
    godbolt.org/z/xYosj7exv or godbolt.org/z/dWM3he4GY Commented Apr 18 at 13:57

1 Answer 1

6

As pointed out in comments, non-static member functions need an instance of the class to be called.

A - If the fooX() functions do not actually need an instance the class:

In that case, the solution would be to either mark the member functions as static or to move them outside of the class.

B - If the fooX() functions actually need an instance of the class:

For the example, let's assume you have the following class:

struct A
{
    bool foo();
};

In that case, you can change the handler signature as follows:

std::function<bool (A*)> handler = &A::foo;

You can call it as follows:

// Create an instance
A a;

// Call the handler with the previously created instance
bool v = handler(&a);

C - Case B but you cannot change the handler's signature

In that case, you can directly bind the handler to an instance with std::bind() when initializing it:

// Create an instance
A a;

// Bind the handler to the previoulsy created instance
std::function<bool ()> handler = std::bind(&A::foo, &a);

Or alternatively, with a lambda function:

std::function<bool ()> handler = [&a]() -> bool {return a.foo();};

Note: Of course, in your case, you can directly use this as instance since the handlers array belongs to the class as well and will probably be initialized in the constructor.

And you can call it with:

bool v = handler();
Sign up to request clarification or add additional context in comments.

7 Comments

I realize this is a matter of preference, but I strongly prefer using a lambda over std::bind in your 3rd scenario. I find it infinitely more readable and maintainable.
When using std::bind(), you need to pass a pointer to the object that will be assigned to the member function's this pointer, eg: std::function<bool ()> handler = std::bind(&A::foo, &a);
@JeremyRichards Actually I find it more verbose and even less readable with a lambda. std::bind is explicit enough and more concise IMHO but well... it's just a matter of opinions. I added the lambda alternative into the answer :)
@RemyLebeau I thought both were correct as this thread suggests. I updated it anyways :)
@JeremyRichards Lambdas are very clunky once you get to functions with arguments other than this, and you want to use perfect forwarding.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.