24

In the code example below, the call to foo works, while the call to bar fails.

If I comment out the call to bar, the code compiles, which tells me the definition of bar itself is fine. So how would bar be called correctly?

#include <iostream>

using namespace std;

int multiply(int x, int y)
{
    return x * y;
}

template <class F>
void foo(int x, int y, F f)
{
    cout << f(x, y) << endl;
}

template <class F>
void bar(int x, int y)
{
    cout << F(x, y) << endl;
}

int main()
{
    foo(3, 4, multiply); // works
    bar<multiply>(3, 4); // fails

    return 0;
}
tajmahal
  • 1,665
  • 3
  • 16
  • 29
  • 1
    Also see [Function passed as template argument](https://stackoverflow.com/q/1174169/608639). – jww Nov 26 '17 at 11:50

2 Answers2

40

The problem here is, multiply is not a type; it is a value but the function template bar expects the template argument to be a type. Hence the error.

If you define the function template as:

template <int (*F)(int,int)> //now it'll accept multiply (i.e value)
void bar(int x, int y)
{
    cout << F(x, y) << endl;
}

then it will work. See online demo : http://ideone.com/qJrAe

You can simplify the syntax using typedef as:

typedef int (*Fun)(int,int);

template <Fun F> //now it'll accept multiply (i.e value)
void bar(int x, int y)
{
    cout << F(x, y) << endl;
}
Nawaz
  • 353,942
  • 115
  • 666
  • 851
8

multiply is not a type, it's a function. In that context, it decays to a function pointer. However, bar is templated for a type which, again, multiply is not.

Nawaz already answered the question the other way around (how to change the definition of bar to be used with functions), but to answer your explicit question of how to call bar as you have it, you need a suitable type, like this:

struct Type {
  const int result;
  Type(int x, int y): result(x * y) {}
  operator int() const { return result; }
};

// usage
bar<Type>(x, y);

// (edit) a suitable type doesn't necessarily mean a new type; this works as well
// if you aren't trying to solve any specific problem
bar<std::string>(64, 64);
eq-
  • 9,986
  • 36
  • 38
  • If he is going to use this, then he needs to change `bar` as well. The syntax `F(x,y)` should become `F(x,y)()`. – Nawaz Jun 03 '12 at 15:04
  • @Nawaz No, `Type` isn't actually a functor. It's just a type with a suitable constructor and a stream output overload (in this case a suitable conversion operator that already has a stream output overload). (see http://ideone.com/AgQGc) – eq- Jun 03 '12 at 15:17
  • Ohh.. I overlooked that... possibly because a functor would be a better alternative here, therefore I was expecting that. – Nawaz Jun 03 '12 at 15:21