Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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'?

like image 429
Rankaba Avatar asked Sep 16 '14 14:09

Rankaba


People also ask

Can a template function be overloaded?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

Can we pass Nontype parameters to templates?

Template classes and functions can make use of another kind of template parameter known as a non-type parameter. A template non-type parameter is a template parameter where the type of the parameter is predefined and is substituted for a constexpr value passed in as an argument.

What is the difference between function overloading and templates?

What is the difference between function overloading and templates? Both function overloading and templates are examples of polymorphism features of OOP. Function overloading is used when multiple functions do quite similar (not identical) operations, templates are used when multiple functions do identical operations.

What are the restrictions on overloaded function?

Restrictions on overloadingAny two functions in a set of overloaded functions must have different argument lists. Overloading functions that have argument lists of the same types, based on return type alone, is an error.


4 Answers

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);});
like image 93
Mike Seymour Avatar answered Oct 15 '22 06:10

Mike Seymour


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.

like image 35
Stuart Olsen Avatar answered Oct 15 '22 05:10

Stuart Olsen


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;
}
like image 30
dseminara Avatar answered Oct 15 '22 04:10

dseminara


Yes:

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

or:

bar<int(*)(int)>(3, &foo);
like image 21
Piotr Skotnicki Avatar answered Oct 15 '22 04:10

Piotr Skotnicki