18

I'm trying to figure out a way of how to be able to assign a function pointer to functions with different number of arguments.

I have a while loop which takes a number of different functions as a conditional statement, so instead of writing multiple while loops with exactly the same code inside I'd like to have one with a function pointer. All the functions are of format bool f(...). I think some code will best illustrate what I mean:

int a, b, c, d;
MyClass* my_class;

typedef bool (MyClass::*my_fun_t)();
my_fun_t my_fun;

if (condition1)
    my_fun = &MyClass::function_one();
else if (condition2)
    my_fun = &MyClass::function_two(a, b);
else if (condition3)
    my_fun = &MyClass::function_three(a, b, c);
else if (condition4)
    my_fun = &MyClass::function_four(a, b, c, d);

while ((my_class->*my_fun)()) 
{ ... }

Now this obviously doesn't work because the functions have different signatures. Is it at all possible to make it work in a similar fashion? Are functoids something I should look at?

jaho
  • 4,852
  • 6
  • 40
  • 66
  • How would you know how to apply that function pointer if you don't know how many arguments it takes? – mfontanini Jun 14 '12 at 16:30
  • Note that your syntax of assignment to a function pointer is invalid anyway, you are *invoking* the functions, taking the result, getting a pointer to its temporary storage, and assign *that* to the function pointer you declared beforehand. – Konrad Rudolph Jun 14 '12 at 16:31
  • Yeah I know it's not quite a valid syntax. It just shows the idea. – jaho Jun 14 '12 at 16:32

4 Answers4

9

You could use std::function<> and std::bind().

#include <functional>

using std::placeholders::_1;

typedef std::function<bool(MyClass&)> my_fun_t;
my_fun_t my_fun;

if (condition1)
    my_fun = std::bind(&MyClass::function_one, _1);
else if (condition2)
    my_fun = std::bind(&MyClass::function_two, _1, a, b);
else if (condition3)
    my_fun = std::bind(&MyClass::function_three, _1, a, b, c);
else if (condition4)
    my_fun = std::bind(&MyClass::function_four, _1, a, b, c, d);

while (my_fun(my_class)) { ... }

These assumes you will use C++11. If you can't use C++11 but can use TR1, replace all std:: with std::tr1::. There is also a Boost implementation.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
5

This works for me:

#include <iostream>
#include <cstdarg>

using namespace std;

class MyInterface
{
public:
    virtual bool func(int argc, ...) = 0;
};

class MyImpl : public MyInterface
{
public:
    virtual bool func(int argc, ...);
};

bool MyImpl::func(int argc, ...)
{
    va_list varargs;
    va_start(varargs,argc);
    cout << "Arguments passed:" << endl;
    for(int i = 0; i < argc; ++i)
    {
        // expect double values
        double val = va_arg(varargs,double);
        cout << val << endl;
    }
    va_end(varargs);
    return true;
}

typedef bool (MyInterface::*MyFunc)(int, ...);

int main() {

    MyImpl impl;
    MyInterface* interface = &impl;
    MyFunc pfunc = &MyInterface::func;

    if(!(interface->*pfunc)(2,double(3.14),double(2.72)))
    {
        return 1;
    }
    return 0;
}

Output:

Arguments passed:
3.14
2.72

Obviously you CAN declare and use function pointers for (member-)functions using variable arguments.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
3

You want std::function, a polymorphic function object, and std::bind to create function objects by binding arguments to the parameters of other functors.

If you can't use C++11, then boost::function and boost::bind are equivalent, although slightly more restrictive.

std::function<bool()> my_fun;

if (condition1)
    my_fun = std::bind(&MyClass::function_one, my_class);
else if (condition2)
    my_fun = std::bind(&MyClass::function_two, my_class, a, b);
else if (condition3)
    my_fun = std::bind(&MyClass::function_three, my_class, a, b, c);
else if (condition4)
    my_fun = std::bind(&MyClass::function_four, my_class, a, b, c, d);

while (my_fun()) 
{ ... }
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 1
    If you can use C++ 11 then you can also use lambda functions and pull the variables from the enclosing lexical scope. Whichever you prefer, I guess. – user268396 Jun 14 '12 at 16:35
  • @user268396: Probably. For the time being, I'm stuck with a compiler that doesn't support lambdas, so I don't know much about them. – Mike Seymour Jun 14 '12 at 16:36
2

I'm trying to figure out a way of how to be able to assign a function pointer to functions with different number of arguments.

You can’t. Function pointers are specific to one function signature. This is entirely logical: how would you invoke such a function? (Yes, C allows invoking functions without specifying in their declaration how many parameters the function has, but this doesn’t work in C++ since it subverts the type system.)

Are functoids something I should look at?

Generally yes, but they don’t solve this problem.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Hmm, but just the 'signature' of a function with variable arguments is still unique, isn't it? The '...' variable arguments part is at least just a camouflage of 'va_list' used inside the functions implementation. Invoking such a function through a function pointer wouldn't (shouldn't) differ anyhow from invoking such function in the usual way (with a variable list of arguments). – πάντα ῥεῖ Jun 14 '12 at 16:41
  • @g-makulik Variable arguments work, but that’s a specific signature, it’s not the same as binding to different function signatures. – Konrad Rudolph Jun 14 '12 at 16:54
  • Ahh, I see your point!. But the OP didn't mention binding explicitely (may be I read his 'pseudo' code wrong). Using interface definitions (polymorphism) it might still be possible to achieve what the OP wants (intended). – πάντα ῥεῖ Jun 14 '12 at 18:02