13

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().

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
leemes
  • 44,967
  • 21
  • 135
  • 183
  • For the mentioned case, you could just create a tuple from the var arg, and the use tuplesize. Maybe tuples are easier to work with, with whatever else you have in mind? – Skeen Mar 23 '13 at 00:43
  • @Skeen This was just a very minimalistic example at which the basic problem can be easily be discussed. Of course, I need something more complex. AFAIK, tuple only works with types, not with values. – leemes Mar 23 '13 at 00:52
  • 1
    Tuples can store data as well and they seem a lot easier to work with if you ask me. – Skeen Mar 23 '13 at 00:54

1 Answers1

19

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);
    //         ^^^^^^^^^
    }
};
Andrzej Budzanowski
  • 1,013
  • 11
  • 17
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Oh my gosh, totally forgot about overloading. Thanks! (off topic: LWS > ideone?) – leemes Mar 23 '13 at 00:44
  • Of course there is sizeof, the `count` was just the simplest example I could come up with, which still demonstrates the basic problem. – leemes Mar 23 '13 at 00:48
  • @leemes: Yes, I realized that, I only mentioned `sizeof...` for the sake of completeness, but I understand your intent – Andy Prowl Mar 23 '13 at 00:49
  • Okay. By the way: I just found out that `template` can be anonymous, but `template` can't. If I understand it correctly: the base case needs to be a template. If I want it to be empty, I still have to say `template`, but SOMETHING can't be empty. A variadic template with `typename` will accept types, but there are never types (at least when not mis-using it). I first wrote `char...` as the base case, but this was ambiguous, of course. So this `typename...` is a hack for this "problem"? – leemes Mar 23 '13 at 00:51
  • 1
    @leemes: A parameter pack can be anonymous, and `SOMETHING` can be empty for function templates: see [here](http://liveworkspace.org/code/N6QE5$48). The `typename...` is a trick to make the call non-ambiguous – Andy Prowl Mar 23 '13 at 00:56