12

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?

Emily L.
  • 5,673
  • 2
  • 40
  • 60

4 Answers4

8

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();
}
Werner Erasmus
  • 3,988
  • 17
  • 31
  • congratulations for your first points – Saksham Aug 01 '13 at 11:20
  • Thanks. I see I need a reputation to upvote someone... Hence I answered a question. – Werner Erasmus Aug 01 '13 at 11:22
  • 2
    Didn't the OP wanted it without using functors? (quote: "Is this possible to do without involving functors?") – mr_georg Aug 01 '13 at 11:49
  • 1
    I specifically stated I did not want to use a functor. I can't change the signature or calling syntax of `f`. – Emily L. Aug 01 '13 at 12:57
  • How about write an adapter that adapts f to the given functor. – Werner Erasmus Aug 01 '13 at 13:45
  • Apologies for the code that did not compile. I never called f in my test. It compiles now. The Adapter needs to have a constructor to accept T and a conversion operator for the return value. – Werner Erasmus Aug 01 '13 at 14:59
  • I accepted this answer as it was the closest to what I wanted. However do I believe there is a possibility that the adapter class could be made more generic to simplify syntax. I just don't have time to look into it :) – Emily L. Aug 14 '13 at 10:26
7

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.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 1
    ...in C++11, if your compiler supports template aliases. MSVC 2013 *still* doesn't – SteveLove Aug 01 '13 at 11:33
  • I wanted to avoid the duplication of the template arguments, this is supposed to save me from typing/copypaste a lot in my unit tests. Appart from that, this is the best answer so far. – Emily L. Aug 01 '13 at 13:03
0

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.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Yes I know, I was looking for some trickery just to avoid changing my production code to make unit testing code more neat. – Emily L. Aug 01 '13 at 12:56
0

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.

JSQuareD
  • 4,641
  • 2
  • 18
  • 27