2

So in C++ we can pass functions as template parameters like so:

template <typename func>
int tester(func f)
{
    return f(10);
}

So I have a template class which uses a function, and I've been using it like this, where each time I would pass the function and a variable to it.

template <typename type_t>
class TCl
{
    ...
    template <typename func>
    int Test(func f, type_t Var>
    {
         // Blah blah blah
    }
};

But I would like to make the function one of the class template parameters to make it easier to use. So I first tried this:

template <typename func>
template <typename type_t, func f>
class TCl
{
    ...
};

But when I compile this I get:

Compiler Error C3857: multiple type parameter lists are not allowed

Because God forbid my code should actually compile the first time I try it.

Now my problem has been that while I know the parameters types for the function (in this case size_t, size_t), the return type could be anything, so long as there is a proper comparison operator for type_t.

After several hours of reading online, I found a working solution.

template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl
{
    ...
};

While it work, it kind of ruins the aesthetic of the code. And I would greatly prefer something like in the original example where I specify a func type, and don't have to worry about specifying the return type.

So does anyone have any suggestions?

Also, no Boost.

EDIT: SOLVED!

Thank you guys. I used Jarod42's solution.

@Drax & Lightness Races in Orbit:

I had considered placing the type before hand, but it would have placed the burden on the programmer to define the function pointer in order to use it, which seemed unnecessarily cruel :)

Jarod42 however solved that using macros and the decltype operator, which I had completely forgotten about.

There was a slight problem with your example Jarod42.

#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>

Generates an error: error C1001: An internal error has occurred in the compiler.

This solves it.

#define TCl_T(type_t, function) Tcl<type_t, decltype(&function), function>

Apparently we have to specify that it is a pointer.

Once again, thanks for the help guys!

  • 1
    What's wrong with `template `? Edit: Oh, you don't want to pass the function as an argument to `Test`? – Joseph Mansfield Jan 15 '14 at 10:25
  • They are called *"Class/function templates"*, not *"Template classes/functions"* – Manu343726 Jan 15 '14 at 10:44
  • This looks a lot like the problem I had [here](http://stackoverflow.com/questions/21049359/c-template-specialization-overloading). It looks to me that there is a need for template-non-type-parameter-deduction when dealing with class-templates. Even though macro's are evil and should be avoided, the answer below from Jarod42 is the only solution when you need aesthetics. – JorenHeit Jan 15 '14 at 11:01
  • `we can pass functions as template parameters` While this is true (through function pointers), you're only passing a function _type_ as a template parameter, and the function pointer itself as a normal function argument. I think you realise this, though, since your goal is to start passing the function pointer itself as a template argument. – Lightness Races in Orbit Jan 15 '14 at 11:06
  • May be related to: [Inferred return type when passing function by template](http://stackoverflow.com/questions/15190605/inferred-return-type-when-passing-function-by-template/15190695#15190695) – Jarod42 Jan 15 '14 at 11:17

3 Answers3

2

With:

template <typename type_t, typename ret_t, ret_t f(size_t, size_t)>
class TCl;

You may use a Macro:

#define TCl_T(type_t, function) Tcl<type_t, decltype(function(0, 0)), function>

And then use it like:

// bool my_func(size_t, size_t);
TCl_T(int, my_func) tcl; // tcl is a Tcl<int, bool, my_func>

And if you change TCl to:

template <typename type_t, typename prototype_t, prototype_t f>
class TCl;

You may use a Macro:

#define TCl_T(type_t, function) Tcl<type_t, decltype(function), function>
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

Well just put the template parameters on the same line :

template <typename type_t, typename func, func f>
class TCl
{
    ...
};
Drax
  • 12,682
  • 7
  • 45
  • 85
1

And I would greatly prefer something like in the original example where I specify a func type, and don't have to worry about specifying the return type.

Okay, so simply do that! :-) I don't understand why you have gone from passing the entire function type as a template argument, to splitting it up into return type and parameter types. And, in doing so, you introduced your stated problem. But you didn't explain why you made this change.

Why not simply:

template <typename type_t, typename func_t, func_t f>
class TCl
{
    // ...
};

This is the logical evolution of your own approach, is it not?

Here's an example that works:

#include <iostream>

template <typename type_t, typename func_t, func_t f>
struct T
{
    T() { f(); }

    type_t a;   /**< Irrelevant here, but gives your `type_t` something to do */
};

void foo() { std::cout << "A\n"; }
int  bar() { std::cout << "B\n"; return 0; }

int main()
{
    T<int, void(*)(), &foo> t1;
    T<int, int (*)(), &bar> t2;
}

// Output:
//  A
//  B

Live demo

Shame you can't use more deduction in the template-argument-list. Jarod42 had an interesting idea with macros in order to shorten the call, though I'm not sure it improved the aesthetic.

I wonder whether this means that your assertion:

make the function one of the class template parameters to make it easier to use

is false.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055