tags:

views:

211

answers:

8

As weird as it sounds, I need to call a function in C++, for which I do not know the signature. Basically, I want to let the user specify a list of arguments, and argument types, and then attempt to call a given function with these arguments. I would then like to know if the function call worked or not, and if it (miraculously) did, what is the return value (provided that the return type is not void). Is there any way to achieve that? Thanks.

A: 

It doesn't sound too weird, but you still can't do it in C++. The signatures of C++ functions are checked at compile time. The best you can do is pass a vector, or similar container, containing your function parameters to the function. Even then, the types (or at least the base type, if you use inheritance) would have to be known at compile time.

anon
@Neil Butterworth: Your conclusion might be right, but your reasoning is fallacious. The same true of C# (statically typed), but it is possible to do what the OP is requesting there using reflection. Yes, I know C++ does not have reflection capabilities.
Jason
Of course. C++ allows you to do anything, but at what effort? It seems unlikely the OP wants to write a general-purpose reflection mechanism for C++.
anon
@Neil Butterworth: I agree with that. And the question suggests a big design smell.
Jason
And a possible huge security hole.
ScaryAardvark
AS Neil said anything is possable. But what the OP is asking for is not practical to implement in a language like C++. It is basically not designed to dynamic function linkage at runtime.
Martin York
Well, as others have pointed out, you can use variant types like boost::any. Those of us who have experienced the joys of such types in the past (for example in CORBA) may feel they would rather eat their own heads.
anon
He didn't actually *say* the signatures weren't known at compile time, just that his service didn't know them.
T.E.D.
What he actually said was "for which I do not know the signature"
anon
A: 

If you have access to C++ compiler during run-time, you can write the postulated call into a file, compile it, then link it in dynamically as a DLL and try to run it. If the argument types are wrong, or the function does not exist, the DLL run-time linkage fails; otherwise the function gets called and you get the return value out.

antti.huima
+7  A: 

Let your functions take a list of variant data types, e.g. std::vector<boost::any> and have them return a bool indicating success or throw exceptions on failure.

If you are ok with registering the exposed functions at compile time, you don't even have to place that restriction on your functions and you can instead generate glue code for the neccessary conversions.

Georg Fritzsche
+1 boost::variant could also be used
Emile Cormier
And if your function needs to return values of differing types, return a variant. Or some other discriminated type. Boost is not required. You could hand roll something for your specific needs pretty easily.
John Dibling
That is, a `union`. I think `variant` would be a very good idea, though… speaking VERY relatively.
Potatoswatter
+3  A: 

Of course you can do that at run time. Gdb, for one, does it. But it requires a lot of work and understanding of the target environment. I suspect there might be a better way to do what you want.

Richard Pennington
Gdb doesn't do it "in C++", though. "Understanding of the target environment" radically changes the problem.
Steve Jessop
A: 

Well, if you are flexible about the mechanisim, you can do this kind of thing using dynamic dispatch.

What you do is create an abstract base class that has a "run it" method returning a return value. Then you have an engine that keeps a list of pointers to objects of this (abstract) base class, which the clients can supply to you via some kind of registration call.

The clients write their own implementations of "run it" that can do whatever they need done, as long as they properly fill out the return value for your engine when they are done. Their "custom parameters" are implemented as extra members to their version of the class, that can be filled out when they construct the object, or by a separate call.

This gives you what you need to call their routine,run it, and check the result, without having to know what their custom parameters are, or exactly what their routine does.

T.E.D.
A: 

This sounds like a sitter for including a dynamically typed scripting language in your app. Embed something like Lua or Python, make the functions you want to be callable available to the scripting language. Or, if you're trying to implement such a thing, look at Boost::Python for a precedent of how to go about it.

Andrew McGregor
A: 

This is a nonsensical question, since if the user (who is calling from c-code) does not know the types of the argument at compile-time, he will not be able to supply the arguments of the correct type, even if it were possible to construct a dynamically typed function pointer.

Even the gdb example expressed in another answer makes the assumption that the user has variables of the appropriate and known type at the point of the call.

Since this is true, I infer that the user does know the correct types of the argument, and this then becomes a question of how to create a function at compile-time that takes a set of arguments of known type.

This is simply achieved: If the user has an int and two floats and hopes to get an int in return, and wishes to call the supposed function swizzle whose type therefore must be int (IIIF*)(int, int, float), then simply declare a pointer of this type, use ldload to get the function swizzle, and invoke it.

There are, however, some special cases of this that you may be able to achieve, for instance, if all the arguments are pointers.

Note that known at compile time includes cases such as templates, whose values are inferred at compile time from explicit or implicit type information at the point and template instantiation time.

Alex Brown
A: 

How about using rvalue references in c++ox?

template<typename Function>
void FunCall( Function&& f)
{
    f();
}

void Fun_Int(int x)
{
    using std::cout;
    using std::endl;

    cout << "I''m Fun_Int with " << x << endl;
}

void Fun_Str(const string& str1)
{
    using std::cout;
    using std::endl;
    cout << "I'm Fun_Str with " << str1 << endl;

}

void RvaluesDemo()
{
    for (int i = 0; i < 5; i++)
    {
        FunCall([&]
        {
            Fun_Int(i);
        });
    }

    string str = "ABCDEF";

    for (int i = 0; i < str.size(); i++)
    {
       ostringstream os;
       os << str[i];

        FunCall([&]
        {
            Fun_Str(os.str());
        });
    }
}
Jagannath