3

Considering this following code :

class A
{
public:
    void aFoo() {}
};

class B
{
public:
    void bFoo() {}
};

class C
{
public:
    void c1Foo() {}
    void c2Foo() {}
};

Regardless the code architecture, is it possible to create a vector of pointers to member functions even if those functions are in multiple classes ?

In this case, inheritance is not a solution because we don't know how many functions we want to use in a class (class C has two functions). But we know they all have the same prototype.

p.i.g.
  • 2,815
  • 2
  • 24
  • 41
  • "is it possible to create a of pointers ..." -- A what of pointers? – Shoe Jun 01 '15 at 12:15
  • what about `std::function` ? – Alejandro Jun 01 '15 at 12:18
  • why not a vector of [`std::function`](http://en.cppreference.com/w/cpp/utility/functional/function). see [this](http://stackoverflow.com/questions/17131768/how-to-directly-bind-member-function-to-stdfunction-in-visual-studio-11) and [this](http://stackoverflow.com/questions/26158504/vector-of-stdfunction-with-different-signatures) – NathanOliver Jun 01 '15 at 12:19
  • 1
    No, they don't have the same prototype. They all have an implicit this parameter. You cannot call these functions without roviding this argument. – n. m. could be an AI Jun 01 '15 at 12:24
  • "class C has two functions". This does not rule out inheritance in any way. – n. m. could be an AI Jun 01 '15 at 12:32
  • Depends on how you want to call them later. – Quentin Jun 01 '15 at 12:35
  • It depends on what you want to achieve. You could create a tuple like this `std::tuple x(&A::aFoo, &B::bFoo, &C::c1Foo)` and call for example the A function as `A a; (a.*std::get<0>(x))()` – linuxfever Jun 01 '15 at 13:16

2 Answers2

10

Member functions of different classes have different types. So in order to have any homogeneous container (like std::vector or std::array) of those you'll need to wrap them in some value type that may represent them all (like boost::variant or boost::any).

On the other hand if all you need are member functions of a specific type (for example void()) and you don't mind passing the object on which they should be called before hand, then you can just store them as std::function<void()> (for this specific example) and just call std::bind on them before storing them in the container.

As an example, given:

A a; B b; C c;
std::vector<std::function<void()>> vector {
    std::bind(&A::aFoo, a),
    std::bind(&B::bFoo, b),
    std::bind(&C::c1Foo, c),
    std::bind(&C::c2Foo, c)
};

you would be able to call:

for (auto fn : vector)
    fn();

Live demo

Shoe
  • 74,840
  • 36
  • 166
  • 272
  • Your solution seems graceful. Is it possible to do the same if functions take one or more parameters ? – user3627616 Jun 01 '15 at 17:48
  • Found the solution for more arguments with placeholders. See this link for more informations http://en.cppreference.com/w/cpp/utility/functional/placeholders. Thank you for your solution ! – user3627616 Jun 01 '15 at 17:58
0

I am not sure what you want to achieve so this may not be very helpful but here it is anyway.

As others have said you cannot create a std::vector for this as the prototypes are different. You can however create a std::tuple like this:

std::tuple<void (A::*)(), void (B::*)(), void (C::*)()> x(&A::aFoo, &B::bFoo, &C::c1Foo);

Assuming you have a an instance of a class, say A a then you can call the function as in (a.*std::get<0>(x))().

If you have stored your objects in a tuple as well, then you can iterate over them. The following code will do just that (assumes you have C++14 and Boost in your system)

#include <iostream>
#include <tuple>
#include <type_traits>
#include <boost/mpl/find_if.hpp>
#include <boost/mpl/deref.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <functional>

class A
{
public:
    void aFoo()
    {
        std::cout << "A" << std::endl;
    }
};

class B
{
public:
    void bFoo()
    {
        std::cout << "B" << std::endl;
    }
};

class C
{
public:
    void c1Foo()
    {
        std::cout << "C1" << std::endl;
    }

    void c2Foo() {}
};

// functor used by boost to iterate over the tuple

template <class Tuple>
struct functor
{
    functor(Tuple t)
    : m_tuple(t)
    {
    }

    template <class X>
    void operator()(X& x) const
    {
        using namespace boost::mpl;
        using iter = typename find_if<Tuple, std::is_same < placeholders::_1, void (X::*)()> >::type;
        using type = typename deref<iter>::type;
        return (x.*std::get<type>(m_tuple))();
    }

private:
    Tuple m_tuple;
};

template <class Tuple>
functor<Tuple> make_functor(Tuple t)
{
    return functor<Tuple>(t);
}

int main()
{
    std::tuple<void (A::*)(), void (B::*)(), void (C::*)() > x(&A::aFoo, &B::bFoo, &C::c1Foo);
    std::tuple<A, B, C> y;
    boost::fusion::for_each(y, make_functor(x));
}

Live demo here: http://coliru.stacked-crooked.com/a/e840a75f5b42766b

p.i.g.
  • 2,815
  • 2
  • 24
  • 41
linuxfever
  • 3,763
  • 2
  • 19
  • 43