/ / Perché l'uso di struct con il parametro variadic template rende simultaneamente due istanze di template? - c ++, templates, c ++ 11, variadic-templates, template-meta-programming

Perché l'uso di struct con il parametro variadic template rende simultaneamente due istanze di template? - c ++, templates, c ++ 11, variadic-templates, template-meta-programming

Mi chiedo perché questo programma non funziona come previsto.

#include <iostream>
#include <utility>
#include <list>

template <typename... Args>
struct prank
: std::integral_constant<std::size_t, 9> {};

template <template <typename...> class C,typename T, typename ...Args>
struct prank<C<T,Args...>>
: std::integral_constant<
std::size_t,
1+ prank<Args...>::value> {};

int main()
{
using T = std::list<int>;
std::cout << prank<T>::value << "n";
}

Ideone

L'output è 11 ma dovrebbe essere 10.

Lasciami spiegare perché:

In main() Noi chiamiamo prank<T> con std::list<int>.

Ha 2 scelta, per regola di risoluzione, sceglie la seconda specializzazione del modello.

Quindi in:

  template <template <typename...> class C,typename T, typename ...Args>
struct prank<C<T,Args...>>

C diventa std::list , T diventa int , Args è empty

Quindi lo ereditiamo da

std::integral_constant<
std::size_t,
1+ prank<Args...>::value>

seconda variabile di std::integral_constant diventare 1 + prank<Args...> , prank<Args...> stesso chiamerà la prima struct di "prank" con il pacchetto Arguments vuoto e dopo aver ereditato da std::integral_constant membro di valore di quella struttura diventa 9.

Così 1+ prank<Args...>::value dovrebbe diventare 1 + 9 = 10 non 11 !!

Ma sembra questo prank<Args...> crea e usa 2 struct allo stesso tempo! (struct prank<C<T,Args...>> e struct prank )

È un bug o sto facendo un errore? (Sto usando gcc 4.8.1)

risposte:

3 per risposta № 1

introduzione

Il problema è che lo stai assumendo std::list ho solo uno template-argument, che causa l'istanza di prank<std::list<int>>, che causerà l'istanziazione di prank<int>.

Questo è tuttavia errato, ed è perché std::list ha un parametro template di default che segue il tuo int, ovvero l'allocatore: std::allocator<int>.

template<class T, class Allocator = std::allocator<T>>
class std::list;
std::list<int> => std::list<int, std::allocator<int>>

Spiegazione

template <typename... Args>
/* (A) -> */ struct prank : std::integral_constant<std::size_t, 9> {};

template <template <typename...> class C,typename T, typename ...Args>
/* (B) -> */ struct prank<C<T,Args...>>
: std::integral_constant<std::size_t, 1+ prank<Args...>::value> {};

istanze, in ordine:

  1. (B) prank<std::list<int, std::allocator<int>>>
  2. (B) prank<std::allocator<int>>
  3. (UN) prank<int>

Il rendimento totale del valore? 11.