ritter
ritter

Reputation: 7699

Function pointer call when signature is given only at runtime

Consider the following situation:

You are given the pointer to a function as a raw pointer

void * function_pointer;

and the arguments to be passed to the function are available as a vector of a union type.

union Types {
  void   *ptr;
  float  *ptr_float;
  double *ptr_double;
  float  fl;
  int    in;
  double db;
  bool   bl;
};

std::vector<Types> arguments;

Thus, the functions' signature is only available in program state (as opposed to be known at compile time)

What would be the recommended way (C++ 11) to make this call ?

It would be possible to alter the arguments vector to something like this:

std::vector< std::pair<int,Types> > arguments;

where the first element of the pair would clearly identify of which type the argument is.

Technically, the signature is only given in the second form. Because only in the first form you can't tell what's the signature like.

Upvotes: 6

Views: 759

Answers (4)

newacct
newacct

Reputation: 122439

In standard C, you must know the signature of a function (at compile time) in order to call it. Calling a function that is of one signature with a function pointer declared of the wrong signature will lead to undefined behavior.

There are libraries that use system-dependent assembly to construct function calls at runtime, like libffi.

Upvotes: 2

beerboy
beerboy

Reputation: 1294

There are existing libraries that can do what you describe, such as C/Invoke:

http://www.nongnu.org/cinvoke/

Upvotes: 1

Brandon
Brandon

Reputation: 23500

I cannot find a way to "bind" the pointer to an std::function object.. perhaps you might figure that out or someone else.. but this is as good as it gets I guess.. It might be do-able in assembly/inline-assembly though.

#include <functional>
#include <iostream>
#include <vector>

void Meh(int X, int Y)
{
    std::cout<<"Meh Arguments-> X: "<<X<<" Y: "<<Y<<"\n";
}

void Foo(std::string T)
{
    std::cout<<"Foo Arguments-> "<<T<<"\n";
}

void FuncAddr(int Args)
{
    std::cout<<"FuncAddr Arguments-> "<<Args<<"\n";
}

typedef void (*FuncPtr)(int);

int main()
{
    void* Ptr = (void*)&FuncAddr;
    std::vector<std::function<void()>> functions;

    functions.push_back(std::bind(Meh, 1, 2));
    functions.push_back(std::bind(Foo, "Hey"));
    functions.push_back(std::bind((FuncPtr)Ptr, 200));  //Perhaps there is a way to "bind" the Pointer without the cast.. Not sure how though..

    for (auto it = functions.begin(); it != functions.end(); ++it)
    {
        (*it)();
        std::cout<<"\n";
    }
}

Upvotes: 0

Cramer
Cramer

Reputation: 1795

Could you not just pass the union itself to the function and let it deal with what it wants? That way all the signatures are the same. If the argument isn't clear from context perhaps even pass two arguments, one saying what the union data is.

Finally if you MUST call a function which you cannot change the signature of I feel the only way is to use a switch, casting the pointer to the right signature before calling.

Upvotes: 1

Related Questions