C++ overloaded function as template argument
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'?
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);});
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.
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;
}
Yes:
bar(3, static_cast<int(*)(int)>(&foo));
or:
bar<int(*)(int)>(3, &foo);