2017-09-19 52 views
18

Rozważmy prosty przykład:są symbolami zastępczymi typów parametrów szablonu non typu zamiennie w przypadku parametru szablonu szablonu

int x; 

template <template <auto> class TT> 
struct Foo { 
    void foo() { 
     TT<(x)> tt; 
     static_cast<void>(tt); 
    } 
}; 

template <decltype(auto)> 
struct Bar { }; 


int main() { 
    Foo<Bar> foobar; 
    foobar.foo(); 
} 

[clang] wydaje się do czynienia z ideą decltype(auto) zastępczego mimo stosowania auto w szablonu parametr szablonu deklaracja bez problemu.

[gcc] z drugiej strony - nie bardzo dobrze:

prog.cc:6:13: error: the value of 'x' is not usable in a constant expression


Jak zwykle - zachowanie, które oczekuje się zgodnie z normą? A może wszystko jest możliwe, a kod jest źle sformułowany (tym razem przypuszczam, że nie, ale nie można tego definitywnie wykluczyć)?

PS. Przepraszamy za złamanie jednego z kompilatorów ponownie;)

+2

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łą. –

+5

@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;)) –

+2

Cóż, ten zasługuje na przegłos, a następnie . –

Odpowiedz

7

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.