12

Chciałbym mieć funkcję szablonu variadic wewnątrz klasy. Argumenty szablonu variadic to znaki, które powinny być przetwarzane w sposób podobny do pętli. Tak więc pomyślałem o napisaniu go jak w haskell z głową/ogonem dzieląc listę, aż osiągnięty zostanie podstawowy przypadek (pusta lista).Funkcja szablonu Variadic: specjalizacja głowa/ogon i pusta podstawa

Jako przykład po prostu policzmy liczbę podanych argumentów (tylko minimalny przykład).

wpadłem na następujący kod:

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

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

W jaki sposób można to osiągnąć? Wiem, że częściowa specjalizacja nie jest obsługiwana dla funkcji. Ale pomyślałem, że specjalizacja szablonu variadic w głowę/ogon i pusta wersja obudowy podstawowej nie jest specjalizacją częściową ale pełną specjalizacją , ale może się mylę? Czy muszę napisać to jako klasę zamiast funkcji?

Znalazłem przykłady (printf), które implementują podstawowy przypadek bez użycia w ogóle składni szablonu. Ale przypuszczam, że mój przypadek jest inny, ponieważ wezwanie do printf nie używa składni szablonu, ale odliczenie , a więc printf(tail...) dzwoni , jeśli jest puste. Z drugiej strony, w moim przypadku, wywołując skrzynkę podstawową, count<>() to nie to samo, co count().

+0

Na wspomnianym przypadku można po prostu stworzyć krotki z arg var, a korzystanie tuplesize. Może krotki są łatwiejsze w pracy z czymkolwiek, co masz na myśli? – Skeen

+0

@Skeen To był bardzo minimalistyczny przykład, na którym można łatwo omówić podstawowy problem. Oczywiście potrzebuję czegoś bardziej złożonego. AFAIK, tuple działa tylko z typami, nie z wartościami. – leemes

+1

Krotki mogą również przechowywać dane i jeśli zadasz mi pytanie, łatwiej im będzie pracować. – Skeen

Odpowiedz

17

Powiedziałbym, że jest zwykle lepszy pomysł, aby przeładowywać szablonów funkcyjnych zamiast je specjalizujący:

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

A oto live example. Chciałbym również wspomnieć, że wbudowany operator sizeof... mogą być wykorzystane do tego celu:

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

O mój Boże, zupełnie zapomniałem o przeciążeniu. Dzięki! (off topic: LWS> ideone?) – leemes

+0

@leemes: Nie ma za co, mam nadzieję, że pomoże! –

+0

Oczywiście jest sizeof, "count" był tylko najprostszym przykładem, jaki mogłem wymyślić, co wciąż demonstruje podstawowy problem. – leemes

Powiązane problemy