Dlaczego istnieje wstrzyknięta nazwa klasy?

147

Ostatnio widziałem dziwną funkcję C ++: wstrzyknięta nazwa klasy .

class X { };
X x1;
class X::X x2; // class X::X is equal to X
class X::X::X x3; // ...and so on...

Ale nie mogę zrozumieć, dlaczego ta funkcja jest konieczna. Czy jest jakaś praktyka, która wymaga tej funkcji?

Słyszałem, że ta funkcja nie istniała w starym C ++. A kiedy został wprowadzony? C ++ 03? C ++ 11?

ikh
źródło
Kolego, możesz spojrzeć na Skype? Nie mogę się z tobą skontaktować
Irinel Iovan

Odpowiedzi:

162

Nazwa wstrzykniętej klasy oznacza, że Xjest zadeklarowana jako element członkowski X, więc wyszukiwanie nazwy wewnątrz Xzawsze znajduje bieżącą klasę, a nie inną, Xktóra może być zadeklarowana w tym samym zakresie obejmującym, np.

void X() { }
class X {
public:
  static X create() { return X(); }
};

Czy create()funkcja tworzy tymczasowy Xobiekt czy wywołuje funkcję X? W zakresie przestrzeni nazw wywołałoby funkcję, więc celem wstrzykniętej nazwy klasy jest zapewnienie, że w treści Xnazwy zawsze znajdzie samą klasę (ponieważ wyszukiwanie nazw rozpoczyna się we własnym zakresie klasy przed zajrzeniem do otaczającego zakres).

Jest to również pomocne w szablonach klas, gdzie wstrzyknięta nazwa klasy może być używana bez listy argumentów szablonu, np. Używając po prostu Foozamiast pełnego identyfikatora szablonu Foo<blah, blah, blah>, więc łatwo jest odwołać się do bieżącej instancji. Zobacz DR 176, aby zobaczyć zmianę między C ++ 98 i C ++ 03, która to wyjaśniła.

Pomysł na nazwę klasy wstrzykiwanej był obecny w C ++ 98, ale terminologia była nowa dla C ++ 03.

C ++ 98 mówi:

Nazwa klasy jest wstawiana do zakresu, w którym jest zadeklarowana natychmiast po wyświetleniu nazwy klasy . Nazwa klasy jest również wstawiana do zakresu samej klasy.

Drugie zdanie zostało zmienione przez DR 147, więc C ++ 03 mówi w [klasa] / 2:

Nazwa klasy jest wstawiana do zakresu, w którym jest zadeklarowana natychmiast po wyświetleniu nazwy klasy . Nazwa klasy jest również wstawiana do zakresu samej klasy; jest to znane jako nazwa klasy wstrzykniętej .

Jeszcze przed C ++ 98 ARM ma z grubsza równoważne sformułowanie, co oznacza, że ​​nazwa klasy może być zawsze używana w treści klasy, aby odwołać się do samej klasy:

Nazwa klasy może być używana jako nazwa klasy, nawet w obrębie listy elementów członkowskich samego specyfikatora klasy.

  • Na przykład,

    class link { link* next; };

Jonathan Wakely
źródło
2
Pytano mnie o to dość często, ale nigdy nie udało mi się stworzyć prostego przykładu wskazującego na problem. Więc +1 Na przykład.
dhein
1
Można to wyraźnie zobaczyć, jeśli uruchomisz clang ++ your_program.cpp -Xclang -ast-dump i zobaczysz swoją klasę, a następnie węzeł podrzędny klasy wstrzykniętej.
xaxxon