template template function parameter

6.3k Views Asked by At

For the life of me, I can't get this simple piece of arcane template magic to work:

template<typename T, int a, int b>
int f(T v){
  return v*a-b; // just do something for example
}

template<typename T, int a, int b, template<typename,int,int> class func>
class C{
  int f(){
    return func<T,a,b>(3);
  }
};

int main(){
  C<float,3,2, f> c;
}

Is this possible to do without involving functors?

4

There are 4 best solutions below

7
On BEST ANSWER

f is supposed to be a class - you have a function.

See below:

// Class acts like a function - also known as functor.
template<typename T, int a, int b>
class f
{
  int operator()(T v)
  {
    return v*a-b; // just do something for example
  }
};

template<typename T, int a, int b, template<typename,int,int> class func>
class C
{
  int f()
  {
    return func<T,a,b>(3);
  }
};

int main()
{
  C<float,3,2, f> c;
}

... And the adapted version if you need to port legacy code (Adapts the function to a class template):

#include <iostream>


template<typename T, int a, int b>
int f(T v)
{
  std::cout << "Called" << std::endl;
  return v*a-b; // just do something for example
}

template<typename T, int a, int b, template<typename,int,int> class func>
struct C
{
  int f()
  {
    return func<T,a,b>(3);
  }
};

template <class T, int a, int b>
struct FuncAdapt
{
  T x_;
  template <class U>
  FuncAdapt( U x )
  : x_( x )
  {}
  operator int() const
  {
    return f<T,a,b>( x_ );
  }
};

int main()
{
  C<float,3,2, FuncAdapt > c;
  c.f();
}
1
On

No, it's not. Even the syntax:

template <typename T, int a, int b, template <typename, int, int> class func>
                                                                  ^^^^^

shows that an argument for a template template parameter must be a class template.

0
On

The reason your compiler is complaining is that you're passing a function (f) as a class to the last template parameter for class C.

Since you cannot pass a function as a template parameter, you should use function pointers or functors. And functors are definitely the cleaner way to do this.

So, although it's possible to achieve what you want without using functors, you really shouldn't try to.

If you want to use function pointers you will be looking at something like this:

template<typename T, int a, int b, int (*func)(T)>
class C{
    int f(){
        return (*func)(3);
    }
};

int main(){
    C< float,3,2,&f<float,3,2> > c;
}

In that case I don't think you would be able to eliminate the code duplication in the declaration of c, but I might be wrong.

2
On

You can solve it through a little trickery:

template<typename T, int a, int b>
int f(T v){
  return v*a-b; // just do something for example
}

template<typename T, int, int>
using func_t = int (*)(T);

template<typename T, int a, int b, func_t<T, a, b> func>
class C{
  int f(){
    return func(3);
  }
};

C<float,3,2, f<float, 3, 2>> c;

First you need a type-alias for the function (func_t above), and you unfortunately need to duplicate the template arguments in the declaration of c.