2

I have a struct called Foo which contains a function that calls whatever method it is passed and returns the value.

struct Foo
{
    unsigned char fooFunc(unsigned char param, unsigned char(getValueMethod)(const unsigned char))
    {
        return getValueMethod(param);
    }
};

I have a method called barFunc...

static unsigned char barFunc(const unsigned char paramA)
{
    return paramA * 2;
}

...which can be nicely passed to fooFunc

Foo foo1;
foo1.fooFunc(10, &barFunc);

But I also want fooFunc to accept member functions, like bazFunc....

struct Baz
{
    unsigned char bazFunc(const unsigned char paramB)
    {
        return paramB * 3;
    }
};

...to be called like this...

Foo foo2;
Baz baz;
foo2.fooFunc(10, ?????);

...but that isn't valid.

Everything I have found on the subject of passing member functions as parameters talks about knowing what class the object comes from before it is called, which means I would have to create 2 functions instead of one.

Is there a way I haven't found yet, which would require only 1 fooFunc method but would support non-member and member functions?

Beakie
  • 1,948
  • 3
  • 20
  • 46
  • You want `boost::bind` (for binding the `this` pointer) and template callables. Technically that will result in more than one `fooFunc` ---method--- member function, but only one `fooFunc` member function template! – Lightness Races in Orbit Oct 03 '14 at 10:15
  • 1
    @Beakie: how about boost? – Piotr Skotnicki Oct 03 '14 at 10:16
  • 1
    I am not worried about precompiled code size, I am worried about compiled code size. It is going ARM. It would be the same as having 2 functions. – Beakie Oct 03 '14 at 10:17
  • use a template function – Richard Hodges Oct 03 '14 at 10:17
  • There is no need for your example for `bazFunc` to be non-static. If you did declare it static, you could pass it to `fooFunc` just like a free function. – eerorika Oct 03 '14 at 10:20
  • @user2079303 I don't want to sound unappreciative of your input. I find this sort of comment frustrating. I create simple examples to explain my point concisely but then there is always someone making comments like this. Am I doing something wrong in my manner or posting? – Beakie Oct 03 '14 at 10:31
  • @Beakie, people often search for complex workarounds when they don't see the simple solution. You didn't specify that you need non-static members and your example didn't show the need for it, so I couldn't be sure what you really need. It's good to make the examples simple, but demonstrating the need for the member to be non-static would hardly have taken away from the simplicity. – eerorika Oct 03 '14 at 11:02
  • `Am I doing something wrong in my manner or posting?` Not at all. Comments are not (just) for criticism. I'm simply trying to help you express your question as clearly as possible. – eerorika Oct 03 '14 at 11:08

3 Answers3

3

Take boost::function<signature> pass the result of boost::bind()

bool free_func(std::string const& arg) { ... }

struct X {
    bool mem_func(std::string const& arg) { ... }
};

...
typedef boost::function<bool (std::string const& name)> func_t;

std::vector<func_t> funcs;
X x;

funcs.push_back(boost::bind(&X::mem_func, x, _1));
funcs.push_back(boost::bind(&free_func, _1));
bobah
  • 18,364
  • 2
  • 37
  • 70
1

With C++11 or boost your task is easy - but because you want to have C++03 solution, then as suggested in comments - use template member function:

struct Foo
{
    template <typename Function>
    unsigned char fooFunc(unsigned char param, Function getValueMethod)
    {
        return getValueMethod(param);
    }
};

Then with free function example you will not to change anything:

Foo foo1;
foo1.fooFunc(10, &barFunc);

With member function - just use C++03 std::mem_fun/bind1st from C++03 <functional>:

#include <functional>
Foo foo2;
Baz baz;
foo2.fooFunc(10, std::bind1st(std::mem_fun(&Baz::bazFunc), &baz));
PiotrNycz
  • 23,099
  • 7
  • 66
  • 112
1

post c++11, as per other answers

pre c++11:

#include <iostream>
#include <functional>


using namespace std;

struct foo_holder {

    template<class T>
    unsigned char foo(unsigned char v, T f) {
        return f(v);
    }

};

unsigned char bar(unsigned char param) {
    return param * 2;
}

struct baz {
    unsigned char bar(unsigned char param) {
        return param * 3;
    }
};

int main()
{
   cout << "Hello World" << endl; 

   foo_holder f;
   baz b;

   cout << static_cast<int>(
    f.foo(6, bar)
    ) << endl;

   cout << static_cast<int>(
    f.foo(6, std::bind1st(std::mem_fun(&baz::bar), &b))
    ) << endl;

   return 0;
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • As my code is not C++11 and I don't want to implement boost, I will take this as my answer (even though I didn't want to create 2 functions, even using templates) as it is the best working solution for my actual implementation. – Beakie Oct 03 '14 at 11:13
  • there's only one definition of `foo_holder::foo` - equivalent to your `Foo::fooFunc`. It's just that it's a template member function. – Richard Hodges Oct 03 '14 at 11:19
  • But if I implement it with 2 calls, one using a member function and one using a non-member function, I will get 2 (compiled) functions, right? – Beakie Oct 03 '14 at 11:29
  • you'll get one function per type. You can remove the std:: prefix if you include the line `using namespace std;` in your cpp file. If you mean, can it be done without the standard library? Yes - you simply write your own versions of std::bind1st etc. – Richard Hodges Oct 03 '14 at 11:50