2015-06-19 15 views
5

Czytałem o szablonach variadic i natknąłem się na ten przykład. Książka wspomina, że ​​aby zakończyć proces rekursji, używana jest funkcja print(). Naprawdę nie mogę zrozumieć jego użycia. Dlaczego autor korzysta z tej pustej funkcji print()?nie może zrozumieć szablonów variadic w C++

void print() // can't get why this function is used 
{ 
} 

template <typename T, typename... Types> 
void print (const T& firstArg, const Types&... args) 
{ 
    std::cout << firstArg << std::endl; // print first argument 
    print(args...); // call print() for remaining arguments 
} 
+0

Po wydrukowaniu ostatniego argumentu zostanie wywołany "pusty" print(). – Banan

+2

Czy rozumiesz funkcje rekurencyjne? Jeśli nie, szablony variadyczne będą zbyt zaawansowanym tematem. – MSalters

+0

@MSalters Otrzymuję funkcje rekursywne całkowicie i zaktualizowałem pytanie –

Odpowiedz

7

Wyrażenie zmiennopozycyjne może przechwytywać argumenty 0 lub więcej.

Weźmy na przykład połączenie print(1). Następnie T przechwytuje int i Types = {} - nie przechwytuje żadnych argumentów. Dlatego wywołanie print(args...); rozszerza się do print();, dlatego potrzebujesz przypadku podstawowego.


W ogóle nie potrzebujesz rekursji. Zawsze używam następujący debuglog funkcji w moim kodu (zmodyfikowany dla potrzeb):

template<typename F, typename ... Args> 
    void 
    print(const F& first, const Args&... args) // At least one argument 
    { 
    std::cout << first << std::endl; 
    int sink[] = 
     { 0, ((void)(std::cout << args << std::endl), 0)... }; 
    (void) sink; 
    } 

Ponieważ zmiennej liczbie argumentów funkcja przyjmuje co najmniej jeden argument, jesteś wolny, aby korzystać z print(void) za cokolwiek teraz podoba.

+0

oh dzięki miły wyjaśnienie –

+0

Mam zaktualizowane pytanie –

+1

Tak ... ta praca wokół rekursji sprawia, że ​​kod jest znacznie brzydszy niż po trochę duplikacji kodu. Na szczęście C++ 17 będzie zawierał wyrażenie "składanka" – KABoissonneault

3

Jest rekurencyjna bo o zmiennej liczbie argumentów częścią szablonu jest zmniejszona każdego połączenia, na przykład wezwanie będzie rekurencyjnie wyglądać następująco

print(1, 2, 3, 4, 5) // firstArg == 1 
         // ...args == 2,3,4,5 

print(2, 3, 4, 5)  // firstArg == 2 
         // ...args == 3,4,5 

print(3, 4, 5)  // firstArg == 3 
         // ...args == 4,5 

print(4, 5)   // firstArg == 4 
         // ...args == 5 

print(5)    // firstArg == 5 
         // ...args == {} 

print() 

The print() jest konieczne w przypadku bazowy przy zmiennej liczbie argumentów lista jest pusta.

3

Rozważ wywołanie funkcji szablonu z pojedynczym argumentem.

print(1); 

firstArg wiązałby do 1 (T = int) i Types... wiązałby się do niczego. Wariantowy pakiet argumentów to zero lub więcej argumentów.

Zatem, w tym połączenia:

print(args...); 

args... jest pusty parametr paczka. Więc to rozszerza się na:

print(); 

Ponieważ funkcja szablon pasuje do każdego połączenia do wydrukowania z jeden lub więcej argumentów, trzeba oddzielną funkcję obsługiwać zerowe argumenty. Która w tym przypadku jest trywialne funkcja:

void print() { } 
3

Przyjmijmy następujący kod:

int a, b, c; 
print(a, b, c); 

Kompilator niejawnie utworzyć następujący kod:

print(const int& firstArg) 
{ 
    std::cout << firstArg << std::endl; // print first argument 
    print(); // call print() for remaining arguments 
} 

print(const int& firstArg, const int& arg2) 
{ 
    std::cout << firstArg << std::endl; // print first argument 
    print(arg2); // call print() for remaining arguments 
} 

print(const int& firstArg, const int& arg2, const int& arg3) 
{ 
    std::cout << firstArg << std::endl; // print first argument 
    print(arg2, arg3); // call print() for remaining arguments 
} 

jak można zobaczyć w Wersja z tylko jednym argumentem, kompilator wywoła metodę "print" bez żadnych argumentów. Ponieważ funkcja drukowania variadic ZAWSZE wymaga co najmniej jednego parametru, to nie będzie pasować ...

+0

Ostatnie zdanie jest nieco błędne - prawdopodobnie oznaczało "Od ** funkcji z ** szablonem variadic ZAWSZE [...]". – Hiura

+0

@Hiura: dzięki za wskazanie, że na zewnątrz -> naprawione – Daniel

Powiązane problemy