Czy Clang słusznie odrzuca kod, w którym zagnieżdżona klasa szablonu klasy jest definiowana tylko poprzez specjalizacje?


17

Biorąc pod uwagę następujący szablon klasy:

template<typename T>
struct Outer
{
    struct Inner;

    auto f(Inner) -> void;
};

definiujemy Innerosobno dla każdej specjalizacji Outer:

template<>
struct Outer<int>::Inner {};

template<>
struct Outer<double>::Inner {};

a następnie raz zdefiniuj funkcję członka fdla wszystkich specjalizacji Outer:

auto Outer<T>::f(Inner) -> void
{

}

ale Clang (9.0.0) narzeka:

error: variable has incomplete type 'Outer::Inner'

auto Outer<T>::f(Inner) -> void

                      ^

Możemy uniknąć błędu kompilatora, podając również definicję Innerwszystkich innych specjalizacji Outer:

template<typename T>
struct Outer<T>::Inner {};

lub definiując fosobno dla każdej specjalizacji:

template<>
auto Outer<int>::f(Inner) -> void
{

}

template<>
auto Outer<double>::f(Inner) -> void
{

}

Zarówno GCC, jak i MSVC akceptują kod początkowy, co nasuwa pytanie; czy jest to błąd Clanga, czy jest to jedyna zgodna implementacja spośród wszystkich trzech?

Wypróbuj Eksplorator kompilatorów


Specjalizacje Wewnętrzne są nieistotne, ich usunięcie nie zmienia wyniku kompilacji.
— n. „zaimki” m.

@ n.'Pronouns'm. Nie jestem pewny co masz na myśli. Zarówno dodanie definicji Innerdla wszystkich innych specjalizacji, jak i zdefiniowanie fosobno dla każdej specjalizacji rozwiązuje błąd kompilacji.
— zepsute

Przeczytajmy to jeszcze raz: usunięcie ich nie zmienia wyniku kompilacji . Nie dodawanie, usuwanie. gcc clang
— n. „zaimki” m.

@ n.'Pronouns'm. Rozumiem teraz, co masz na myśli, ale nadal jest to dziwny komentarz. Chodzi mi o to, że Innerjest zgłaszany jako niekompletny typ, pomimo definicji dla każdej specjalizacji Outer. Wyraźnie Innerbędzie (poprawnie) niekompletny, jeśli usuniesz jego definicje.
— zirytowany

„Wyraźnie, że Wewnętrzna będzie (poprawnie) niekompletnym typem, jeśli usuniesz jej definicję (definicje).” Nie, to wcale nie jest ckear. Specjalizacja jest całkowicie oddzielnym szablonem i nie wpływa w ogóle na główny szablon.
— n. „zaimki” m.

Odpowiedzi:


4

Uważam, że Clang nie zgadza się z odrzuceniem twojego kodu. Musimy zadać sobie pytanie, jak wypada twoja deklaracja funkcji i definicja

auto f(typename T::Inner) -> void;

// ...

template<typename T>
auto Outer<T>::f(typename T::Inner) -> void
{ }

W tym przykładzie T::Innerjest oczywiście typ zależny. Dlatego Clang może nie założyć, że jest niekompletny do momentu utworzenia instancji. Czy to samo dotyczy twojego przykładu? Tak bym powiedział. Ponieważ mamy to w standardzie:

[temp.dep.type]

5 Nazwa jest członkiem bieżącej instancji, jeśli tak jest

  • Niewykwalifikowana nazwa, która, gdy spojrzy się w górę, odnosi się do co najmniej jednego członka klasy, która jest bieżącą instancją lub jej niezależną klasą podstawową. [Uwaga: Może się to zdarzyć tylko podczas wyszukiwania nazwy w zakresie objętym definicją szablonu klasy. - uwaga końcowa]
  • ...

Nazwa jest zależnym elementem bieżącej instancji, jeśli jest ona częścią bieżącej instancji, która, gdy jest sprawdzana, odnosi się do co najmniej jednego elementu klasy, która jest bieżącą instancją.

9 Typ jest zależny, jeśli tak jest

  • ...
  • członek nieznanej specjalizacji,
  • zagnieżdżona klasa lub wyliczenie, które jest zależnym elementem bieżącej instancji,
  • ...

Zatem pierwszy punkt w paragrafie 9 dotyczy sprawy typename T::Inner. To jest typ zależny.

Tymczasem twoja sprawa jest objęta drugim pociskiem. Outer::Innerto nazwa, która znajduje się w bieżącej instancji Outer, ponadto znajduje się w Outersobie, a nie w klasie bazowej. To czyni go zależnym członkiem bieżącej instancji. Ta nazwa odnosi się do zagnieżdżonej klasy. Co oznacza, że ​​obowiązują wszystkie warunki zawarte w drugim pocisku, a zatem Outer::Innerrównież typ zależny!

Ponieważ w obu przypadkach mamy typ zależny, kompilatory powinny traktować je jednakowo jako typy zależne. Mój wniosek jest taki, że GCC i MSVC mają rację.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.