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";
}
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 № 1introduzione
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:
- (B)
prank<std::list<int, std::allocator<int>>>
- (B)
prank<std::allocator<int>>
- (UN)
prank<int>
Il rendimento totale del valore? 11.