Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variadic template function: specialize head/tail and empty base case

I'd like to have a variadic template function inside a class. The variadic template arguments are chars which should be processed in a loop-like manner. So I thought of writing it like in haskell with head/tail splitting the list until a base case (empty list) is reached.

As an example, let's just count the number of arguments given (only a minimal example).

I came up with the following code:

struct MyClass {
    template<char ...X>
    static int count();
};


template<>
int MyClass::count<>() {
    return 0;
}
template<char Head, char ...Tail>
int MyClass::count<Head, Tail...>() {
    return 1 + count<Tail...>();
}

However, this doesn't seem to work:

prog.cpp:12:35: error: function template partial specialization ‘count<Head, Tail ...>’ is not allowed
prog.cpp:12:5: error: prototype for ‘int MyClass::count()’ does not match any in class ‘MyClass’
prog.cpp:3:16: error: candidate is: template<char ...X> static int MyClass::count()

How can I achieve this? I know that partial specialization isn't supported for functions. But I thought that specializing a variadic template into head/tail and empty base case version isn't a partial specialization but a full specialization, but maybe I'm wrong? Do I need to write this as a class instead of a function?

I found examples (printf) which implement a base case without using the template syntax at all. But I guess that my case is different, since the call for printf doesn't use template syntax but type deduction, so printf(tail...) calls printf() if tail is empty. On the other side, in my case, when calling the base case, count<>() isn't the same as count().

like image 867
leemes Avatar asked Mar 23 '13 00:03

leemes


1 Answers

I would say it is normally a better idea to overload function templates rather than specializing them:

struct MyClass {
    template<typename... Tail>
    static int count() {
        return 0;
    }

    template<char Head, char... Tail>
    static int count() {
        return 1 + count<Tail...>();
    }
};

#include <iostream>

int main() {
    std::cout << MyClass::count<'f','o','o'>();
}

And here is a live example. I would also mention that the built-in operator sizeof... could be used for this purpose:

struct MyClass {
    template<char... Chars>
    static int count() {
        return sizeof...(Chars);
    //         ^^^^^^^^^
    }
};
like image 159
Andy Prowl Avatar answered Sep 21 '22 13:09

Andy Prowl