JohnDoe
JohnDoe

Reputation: 189

Calling function from std::array of function pointers

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

Answers (3)

super
super

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

Cheers and hth. - Alf
Cheers and hth. - Alf

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

jfMR
jfMR

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

Related Questions