Mandalf The Beige
Mandalf The Beige

Reputation: 81

C++ Templates: Function as Template Class Parameter

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!

Upvotes: 2

Views: 1930

Answers (3)

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

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.

Upvotes: 1

Drax
Drax

Reputation: 13288

Well just put the template parameters on the same line :

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

Upvotes: 1

Jarod42
Jarod42

Reputation: 217275

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>

Upvotes: 2

Related Questions