21

the simplified version of my code is here

int foo(int x) { return x; } int foo(int x, int y) { return x+y; } template<typename unary_func> int bar(int k, unary_func f) { return f(k); } int main() { bar(3, foo); return 0; } 

Is there a way to tell the compiler what I want to pass as argument is the first `foo'?

4 Answers 4

14

You can give an explicit template argument:

bar<int(int)>(3, foo); 

or cast the ambiguous function name to a type from which the template argument can be deduced:

bar(3, static_cast<int(*)(int)>(foo)); 

or wrap it in another function (or function object) to remove the ambiguity

bar(3, [](int x){return foo(x);}); 
Sign up to request clarification or add additional context in comments.

1 Comment

Actually, in my case, foo is the 4th argument. So best way is static_cast?
9

I handle this problem with the following macro:

#define LIFT(fname) \ [] (auto&&... args) -> decltype (auto) \ { \ return fname (std::forward <decltype (args)> (args)...); \ } 

Given your definitions of foo and bar, you can say

int main() { bar(3, LIFT(foo)); return 0; } 

and the correct overload will be selected. This uses some features of C++14, namely generic lambdas and decltype(auto). If you're using C++11, you can get more or less the same effect with a little more work:

#define DECLARE_LIFTABLE(NAME) \ struct NAME##_lifter \ { \ template <typename... Args> \ auto operator () (Args&&... args) -> decltype (NAME (std::forward <Args> (args)...)) \ { \ return NAME (std::forward <decltype (args)> (args)...); \ } \ } #define LIFT(NAME) (NAME##_lifter {}) DECLARE_LIFTABLE(foo); int main() { bar(3, LIFT(foo)); return 0; } 

If you're using C++98, you're basically stuck with a cast to the appropriate function pointer type.

3 Comments

florianjw.de/en/passing_overloaded_functions.html offers some more explanation of the first macro.
@phimuemue is it the same as fiona.onl/en/passing_overloaded_functions.html ? it just seems the certificate does not work on florianjw.de
@xealits Yes, I think so.
4

No, you can't, because you are calling the function always with only one argument, you need a type with only one argument. Instead, you can use template by value (no typename or class)

One argument:

 int foo(int x) { return x; } int foo(int x, int y) { return x+y; } typedef int (*foo_fcn)(int); template<foo_fcn unary_func> int bar(int k) { return unary_func(k); } int main() { bar<foo>(3); return 0; } 

Two arguments:

 int foo(int x) { return x; } int foo(int x, int y) { return x+y; } typedef int (*foo_fcn)(int, int); template<foo_fcn unary_func> int bar(int k) { return unary_func(k, k); } int main() { bar<foo>(3); return 0; } 

Both:

 int foo(int x) // first foo { return x; } int foo(int x, int y) // second foo { return x+y; } typedef int (*foo_fcn)(int); typedef int (*foo_fcn_2)(int, int); template<foo_fcn unary_func> int bar(int k) { return unary_func(k); } template<foo_fcn_2 unary_func> int bar(int a, int b) { return unary_func(a, b); } int main() { bar<foo>(3,1); // compiler will choose first foo bar<foo>(4); // compiler will choose second foo return 0; } 

Comments

1

Yes:

bar(3, static_cast<int(*)(int)>(&foo)); 

or:

bar<int(*)(int)>(3, &foo); 

1 Comment

Or bar<int(int)>(3, foo).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.