Ogólnie mówiąc, aby odliczenie powiodło się, argument musi mieć tę samą ogólną postać co parametr. Istnieją pewne wyjątki, w których T &&
można wywnioskować z U &
(wybierając T = U &
), ale nie podano takiego wyjątku dla tego przypadku.
14.8.2.5 Wydedukowania argumenty szablon z rodzaju [temp.deduct.type]
8 typ szablonu argumentu T
, szablon szablon argumentu TT
lub szablon bez typu argumentu i
może być wywnioskować, czy P
i A
mieć jedną z następujących form:
[...]
T&
T&&
[...]
To nie jest do końca jasne, ale to wymaga P
(parametr) i A
(argument) i oba mają taką samą formę. Muszą to być zarówno formularze T&
, jak i oba z formularzy T&&
.Wyjątki od okoliczności, w których T &&
można wyprowadzić z U &
, są wykonywane przez zmiany T &&
do zwykłego T
przed dopasowanie zachodzi w ograniczonym zakresie:
10 Podobnie, P
ma postać, która zawiera (T)
, a następnie każdy rodzaj parametru Pi
odpowiedniego -parametrów typu lista z P
jest porównywany z odpowiednim typu parametru Ai
odpowiedniego -parametrów typu lista z A
. Jeśli P
i A
są typami funkcji wywodzącymi się z dedukcji podczas przyjmowania adresu szablonu funkcji (14.8.2.2) lub podczas wnioskowania argumentów szablonu z deklaracji funkcji (14.8.2.6) i Pi
i Ai
są parametrami najwyższego poziomu parametr typu lista- z P
i A
odpowiednio Pi
nastawia jeśli jest to odniesienie RValue do parametru szablonu CV bez zastrzeżeń i Ai
jest lwartością odniesienia, w którym to przypadku rodzaj Pi
zmienia się być szablon typ parametru (tj. T&&
został zmieniony na po prostu T
). [...]
i
14.8.2.1 Wydedukowania argumenty szablonów z wywołania funkcji [temp.deduct.call]
3 [...] Jeśli jest P
wartość rvalue dla parametru szablonu bez cv, a argumentem jest l-value, zamiast "A
" używany jest typ "L-value reference to A
". [...]
, ale nie ma podobnego wyjątku dla twojego scenariusza.
Jest to ta sama zasada, która sprawia
template <typename T> struct S { };
template <typename T> void f(S<const T>) { }
int main() { f(S<void()>()); }
nieprawidłowy: const T
nie można wywnioskować z void()
, choć T = void()
dałby dokładnie ten wynik, a nazywając f<void()>
uda.
Wintermute za usunięte odpowiedź pokazał, że można użyć
template <typename... Types> // vv-- change here
void print_tuple(const std::tuple<Types...>& value)
zamiast: pozwala Types
zostać wyprowadzona jako odniesienia lwartości, jako odniesienia rvalue lub jako nie-referencji, w zależności od rodzaju value
.
Nie musisz nawet specjalnie przechwytywać krotki. Dlaczego nie po prostu 'template void print_tuple (Tuple && value)'? –
0x499602D2
Ponieważ nie było to jasne dla co najmniej dwóch osób: twoja definicja 'print_tuple' * nie zezwala na wywołanie, jeśli argumenty szablonu są jawnie określone jako' print_tuple '. To dobre pytanie, dlaczego kompilator inaczej wyprowadza pierwsze "typy". –
hvd
@hvd Może to być spowodowane tym, że literał łańcuchowy jest lwartością i jest przekazywany jako taki. – 0x499602D2