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.

7
  • "is it possible to create a of pointers ..." -- A what of pointers? Commented Jun 1, 2015 at 12:15
  • what about std::function<void()> ? Commented Jun 1, 2015 at 12:18
  • why not a vector of std::function. see this and this Commented Jun 1, 2015 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. Commented Jun 1, 2015 at 12:24
  • "class C has two functions". This does not rule out inheritance in any way. Commented Jun 1, 2015 at 12:32

2 Answers 2

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

Sign up to request clarification or add additional context in comments.

2 Comments

Your solution seems graceful. Is it possible to do the same if functions take one or more parameters ?
Found the solution for more arguments with placeholders. See this link for more informations en.cppreference.com/w/cpp/utility/functional/placeholders. Thank you for your solution !
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

Comments

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.