Reputation: 189
I can't figure out how to call function pointer stored in std::array
which is member of class.
namespace logic {
class Chance {
std::array<void(logic::Chance::*)(), 15> m_redChances;
};
}
void logic::Chance::redChance1 {
std::cout << "Red chance one\n";
}
logic::Chance::Chance()
{
m_redChances[0] = &Chance::redChance1;
}
It looks fine till now, but when I want to call this function in another member function, nothing seems to work. Only first line compiles, but it doesnt call my function. Rest are giving erros:
logic::Chance::anotherMemberFunction() {
m_redChances[0];
(*m_redChances[0]*)();
(*logic::Chance::m_redChances[0])();
m_redChances[0]();
*m_redChances[0]();
*logic::Chance::m_redChances[0]();
*logic::Chance::m_redChances[0];
*(*m_redChances[0])();
}
operand of "*"must be a pointer type
and
expression precending parentheses of apprent call must have (pointer-to-) function type
EDIT#
So I tried to use std::function
and had to change class design a bit, I want to achieve something like this
struct Foo {
std::array<std::function<void(Foo&)>, 3> funArray;
Foo() {
funArray[0] = &Foo::fun1;
funArray[1] = &Foo::fun2;
}
void fun1() {
std::cout << "fun1\n";
}
void fun2() {
std::cout << "fun2\n";
}
std::function<void(Foo&)> getFunction(int i) {
return funArray[i];
}
};
int main() {
Foo foo;
foo.getFunction(0);
std::cin.get();
}
As you can guess, this isn't calling my function and I again, tried every combination to return this correctly, but cant figure it out, thats the only one that compiles, but does nothing. How can I return a function call of function sotred in std::array
by another function? A bit messy, but hope you get what I mean.
Upvotes: 2
Views: 3809
Reputation: 12928
In your std::function
example you can simply change
foo.getFunction(0);
to instead say
foo.getFunction(0)(foo);
This has to do with the same reason talked about in the other answers, a pointer to member-function is not in itself linked to an object. It needs a this
to work on.
If you want to bind the std::function to a specific object you can use a lambda to do that, like this.
#include <iostream>
#include <array>
#include <functional>
struct Foo {
std::array<std::function<void()>, 3> funArray; // Notice the change in signature to void()
Foo() {
funArray[0] = [&](){ fun1(); }; // Here & is catching this by reference and this lambda will always call fun1 on the current object.
funArray[1] = [&](){ fun2(); };
}
void fun1() {
std::cout << "fun1\n";
}
void fun2() {
std::cout << "fun2\n";
}
std::function<void()> getFunction(int i) {
return funArray[i];
}
};
int main() {
Foo foo;
foo.getFunction(0)(); // We get a function returned, so we need to call if by adding one more () at the end
auto storedFunction = foo.getFunction(1); // We can also store it
storedFunction(); // and call it later
}
Upvotes: 2
Reputation: 145204
A member function needs to be called on an object, to serve as the *this
current object. You use the .*
and ->*
operators to call it with an object. E.g. (o.*mf)( args )
.
Silly-fact noted by Andrei in his Modern C++ Programming book: o.*mf
produces a callable entity that has no type.
In C++11 and later you can use std::function
to effectively store such an object+function pointer pair, as a callable entity. Some other languages support it directly. E.g., it corresponds to a C# delegate.
Example.
#include <array>
#include <iostream>
using namespace std;
struct Foo
{
void blah() { cout << "Blah!" << endl; }
};
auto main()
-> int
{
array<void (Foo::*)(), 3> mf = {nullptr, nullptr, &Foo::blah};
Foo o;
Foo* o_ptr = &o;
(o_ptr->*mf[2])();
}
Upvotes: 1
Reputation: 24738
std::array<void(logic::Chance::*)(), 15> m_redChances
is an array of pointers to a non-static
member function of objects of class Chance
. Therefore, you need to apply the object where the pointed-to member function is going to be called.
In the statement:
(*logic::Chance::m_redChances[0])();
no object is provided. On which object's data is that call going to be performed?
Considering chance
an object of Chance
and chance_ptr
a pointer to an object of the same type, the call would be performed this way:
(chance.*m_redChances[0])();
(chance_ptr->*m_redChances[0])();
That is, by using the operators .*
and ->*
, respectively.
Upvotes: 3