11

I want to write a function that calls another function with its arguments. See how I want that it work:

int sum(int a, int b) { return a + b }
int succ(int a)       { return a + 1 }
int size(char* str)   { return strlen(str) }

int call(???) { ??? }

int main() {
  cout << call(sum, 1, 2) << endl;
  cout << call(succ, 41) << endl;
  cout << call(size, "teste") << endl;
}

Expected output:

3
42
5

How can I write the call function (assuming that the return value is always the same)? The only way that I can think is this:

template<typename T> int call(T func, int a, int b) { return func(a, b) } 
template<typename T> int call(T func, int a)        { return func(a) } 
template<typename T> int call(T func, char* a)      { return func(a) } 

Is there any way to solve this repetition with templates, va_list or anything else?

Intention:

It's for drawing geometry pictures, parsing a function with the parametric equation to be drawed. Example:

Vector2i circle(float t, float radius) {
  return Vector2i(cos(t * 2*PI) * radius, sin(t * 2*PI) * radius);
}
// ...
draw(circle, 10);

The function circle will be called many times inside draw with diferents ts (between 0.0 and 1.0). The others arguments of draw is sent directly to the funcions, 10 will be radius. (Vector2i is a custom class).

6
  • 1
    just curious, why don't you just call the function(s) directly? This obtuse diversion does not seem to serve any purpose. Commented Jul 7, 2011 at 17:06
  • 1
    Can you explain the problem you're actually trying to solve rather than a perceived solution? Commented Jul 7, 2011 at 17:07
  • If you have a compiler that supports variadic templates you could do this, but the question remains ... why do you want to do this? Why not just call the functions directly? Commented Jul 7, 2011 at 17:10
  • 4
    Just use boost::bind (std::bind in 0x). And don't ever use va_list, it's non-type-safe cumbersome crap. Commented Jul 7, 2011 at 17:12
  • It's for drawing geometry pictures, parsing a function with the parametric equation to be drawed. Example: Vector2i circle(float t, float r) {return Vector2i(cos(t*2*PI)*r, sin(t*2*PI)*r)}; and then draw(circle, 10), where the function will be called many times with diferents ts (between 0.0 and 1.0) and the 10 as the r. (Vector2i is a custom class) Commented Jul 7, 2011 at 17:14

3 Answers 3

22

C++0x variadic templates:

template<typename Func, typename... Args>
auto call(Func func, Args&&... args)
-> typename std::result_of<Func(Args...)>::type
{
    return func(std::forward<Args>(args)...);
}
Sign up to request clarification or add additional context in comments.

15 Comments

-1 since he didn't ask for C++0x solution but C++ solution which is assumed on SO not C++0x.
@0A0D: Er, what? C++0x is C++, it's even in the name.
+1 because regardless of pointless bickering over whether c++0x is assumed when someone tags c++, this answer is useful. @0A0D did you look at the tag wiki for c++? It does mention C++0x.
@0A0D: Well, it's a stupid downvote. We specifically mark 0x solutions as 0x to avoid confusion, but that doesn't mean it's suddenly not C++. Plus, in a year tag wiki will change to 0x AND THEN WHAT?
@0A0D: It's good to comment on a downvote. Always state your opinion. But it's ok that people don't agree.
|
3

Add another template variable:

template<typename T, typename U> 
int call(T func, U a) { return func(a) } 

template<typename T, typename U, typename V> 
int call(T func, U a, V b) { return func(a,b) }

3 Comments

Yes, but I also want to make it working with any number of arguments, to call func.
@LBg: That's not what you asked.
the only thing you could do is pass a list of arguments with stdarg, but you would only be able to pass them as a list, not in a proper call. Unless you do a switch on the number of parameters. en.wikipedia.org/wiki/Stdarg.h
2

How about a simple #define for current C++ solution:

#define call(FUNC, ...) FUNC(__VA_ARGS__)

Here is the demo. I would advise to use a better name then a generic name like call as you are using #define.

2 Comments

Variadic macros are introduced with C++0x (but are a common extension since they are valid C99).
@Luc, I think most of the compiler supports it. But anyways, I din't know about this fact.

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.