Функция шаблона Variadic: специализируйте голову/хвост и пустой базовый футляр

Я хотел бы иметь переменную функцию шаблона внутри класса. Параметрические аргументы шаблона - это символы, которые должны обрабатываться в виде петли. Поэтому я подумал написать его, как в haskell с head/tail, разбивая список до тех пор, пока не будет достигнут базовый регистр (пустой список).

В качестве примера позвольте просто подсчитать количество приведенных аргументов (только минимальный пример).

Я придумал следующий код:

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

Однако этот не работает:

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

Как я могу это достичь? Я знаю, что частичная специализация не поддерживается для функций. Но я думал, что специализация вариационного шаблона в голове/хвосте и пустая версия базового варианта - это не частичная специализация, а полная специализация, но, может быть, я ошибаюсь? Нужно ли писать это как класс вместо функции?

Я нашел примеры (printf), которые реализуют базовый пример без использования синтаксиса шаблона. Но я предполагаю, что мой случай отличается, так как вызов printf не использует синтаксис шаблона, а выводит тип, поэтому printf(tail...) вызывает printf(), если tail пуст. С другой стороны, в моем случае при вызове базового случая count<>() не совпадает с count().

Ответ 1

Я бы сказал, что лучше всего перегрузить шаблоны функций, а не специализировать их:

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'>();
}

И вот пример live. Я также хотел бы упомянуть, что для этой цели можно использовать встроенный оператор sizeof...:

struct MyClass {
    template<char... Chars>
    static int count() {
        return sizeof...(Chars);
    //         ^^^^^^^^^
    }
};