Oryginalna odpowiedź tutaj miała Foo<Bar>
źle sformułowany, obecnie uważam, że jest dobrze uformowany. Ale ostatecznie, opierając się na klangach.
I rzeczywiście, że nawet Foo<Bar>
jest źle sformułowane. Nowe zasady, po P0522 są następujące:
A template-argument matches a template template-parameterP
when P
is at least as specialized as the template-argumentA
gdzie:
A template template-parameterP
is at least as specialized as a template template-argumentA
if, given the following rewrite to two function templates, the function template corresponding to P
is at least as specialized as the function template corresponding to A
according to the partial ordering rules for function templates ([temp.func.order]). Given an invented class template X
with the template parameter list of A
(including default arguments):
- Each of the two function templates has the same template parameters, respectively, as
P
or A
.
- Each function template has a single function parameter whose type is a specialization of
X
with template arguments corresponding to the template parameters from the respective function template where, for each template parameter PP
in the template parameter list of the function template, a corresponding template argument AA
is formed. If PP
declares a parameter pack, then AA
is the pack expansion PP...
([temp.variadic]); otherwise, AA
is the id-expressionPP
.
If the rewrite produces an invalid type, then P
is not at least as specialized as A
.
Co oznacza, że w celu sprawdzenia, czy sama Foo<Bar>
jest w porządku, możemy syntetyzować:
template <decltype(auto) I> struct X;
template <auto I> void __f(X<I>); // P
template <decltype(auto) I> void __f(X<I>); // A
Wszystkie rodzaje tutaj są ważne (więc ostatnie stwierdzenie nie ma zastosowania). Teraz zazwyczaj, gdy wykonujemy częściowe porządkowanie, jest to w kontekście albo rozdzielczości przeciążenia, albo wyboru specjalizacji szablonu klasy, w takim przypadku szukamy szablonu funkcji "more specialized", gdziejest more specialized thanG
, jeśli jest co najmniej tak wyspecjalizowany as G
i G
nie jest co najmniej tak wyspecjalizowana jak F
.
Ale w tym kontekście nie dbamy o to, który jest bardziej wyspecjalizowany. Potrzebujemy tylko P
, aby być co najmniej tak wyspecjalizowanym jak A
. Wszystko to oznacza, że odliczenie musi odnieść sukces od A
do P
. Więc jeśli zsyntetyzujemy jakiś unikalny typ U
o pewnej wartości V
, czy możemy wywnioskować X<I>
z X<V>
? Tak. Dlatego też P
jest co najmniej tak wyspecjalizowany jak A
, więc szablon-argument Bar
pasuje do parametru szablonu TT
.
Teraz, podając ten punkt, powiedziałbym, że to błąd klang. Szablon-parametr parametr-szablonu to template <auto>
, którego powinniśmy użyć do sprawdzenia poprawności wyrażenia. Z parametrem szablonu non-type auto
, spróbujemy użyć wartości x
- ale x
nie jest poprawnym wyrażeniem stałym, więc powinno się to nie udać.clang wydaje się bezpośrednio używać template <decltype(auto) >
- co nie jest pewne.
To powiedziawszy, nie jestem pewien, czy ta sprawa została wzięta pod uwagę - nie widzę żadnego sformułowania w ten czy inny sposób i warto zgłosić problem.
Nie widzę, jak określenie '(x)' dla parametru szablonu, gdzie 'x' jest zmienną, jest poprawne dla każdego rodzaju szablonu. Ostatnio sprawdziłem, że parametr szablonu może być tylko typem lub stałą. –
@SamVarshavchik dla 'decltype (auto)' jest rozwiązany na odwołanie do zmiennej tak długo, jak długo zmienna ma połączenie oczywiście (ostatni raz sprawdziłem, czy to było rzeczywiście poprawne;)) –
Cóż, ten zasługuje na przegłos, a następnie . –