Gegeben die folgende Klassenvorlage:
template<typename T>
struct Outer
{
struct Inner;
auto f(Inner) -> void;
};
Wir definieren Inner
separat für jede Spezialisierung von Outer
:
template<>
struct Outer<int>::Inner {};
template<>
struct Outer<double>::Inner {};
und definieren Sie dann die Elementfunktion f
einmal für alle Spezialisierungen von Outer
:
auto Outer<T>::f(Inner) -> void
{
}
aber Clang (9.0.0) beschwert sich:
error: variable has incomplete type 'Outer::Inner'
auto Outer<T>::f(Inner) -> void
^
Wir können dem Compilerfehler ausweichen, indem wir auch eine Definition Inner
für alle anderen Spezialisierungen von Outer
:
template<typename T>
struct Outer<T>::Inner {};
oder indem f
für jede Spezialisierung separat definiert wird :
template<>
auto Outer<int>::f(Inner) -> void
{
}
template<>
auto Outer<double>::f(Inner) -> void
{
}
Sowohl GCC als auch MSVC akzeptieren den ursprünglichen Code, der die Frage aufwirft. Ist dies ein Clang-Fehler oder ist es die einzige konforme Implementierung von den drei?
Inner
für alle anderen Spezialisierungen als auch dasf
separate Definieren für jede Spezialisierung beheben den Kompilierungsfehler.Inner
trotz Definitionen für jede Spezialisierung derOuter
Bereitstellung als unvollständiger Typ gemeldet wird. Es ist klar,Inner
dass (korrekt) ein unvollständiger Typ ist, wenn Sie seine Definition (en) entfernen.Antworten:
Ich glaube, Clang ist falsch, Ihren Code abzulehnen. Wir müssen uns fragen, wie sich Ihre Funktionsdeklaration und -definition verhält
In diesem Beispiel
T::Inner
handelt es sich offensichtlich um einen abhängigen Typ. Daher kann Clang nicht davon ausgehen, dass es bis zur Instanziierung unvollständig ist. Gilt das auch für Ihr Beispiel? So würde ich sagen. Denn wir haben dies im Standard:Der erste Punkt in Absatz 9 behandelt also den Fall
typename T::Inner
. Das ist ein abhängiger Typ.In der Zwischenzeit wird Ihr Fall von der zweiten Kugel abgedeckt.
Outer::Inner
ist ein Name, der in der aktuellen Instanziierung von gefunden wirdOuter
, außerdem in sichOuter
selbst und nicht in einer Basisklasse. Das macht es zu einem abhängigen Mitglied der aktuellen Instanziierung. Dieser Name bezieht sich auf eine verschachtelte Klasse. Dies bedeutet, dass alle Bedingungen im zweiten Aufzählungszeichen gelten, wodurch auchOuter::Inner
ein abhängiger Typ entsteht!Da wir in beiden Fällen einen abhängigen Typ haben, sollten Compiler sie als abhängige Typen gleich behandeln. Mein Fazit ist, dass GCC und MSVC Recht haben.
quelle