Deklaracje w C++
Z tego co zrozumiałem, deklaracje / inicjalizacje w C++ są deklaracjami z 'typem bazowym', po których następuje oddzielona przecinkami lista deklaratorów.
Rozważmy następujące deklaracje:
int i = 0, *const p = &i; // Legal, the so-called base type is 'int'.
// i is an int while p is a const pointer to an int.
int j = 0, const c = 2; // Error: C++ requires a type specifier for all declarations.
// Intention was to declare j as an int and c an as const int.
int *const p1 = nullptr, i1 = 0; // p1 is a const pointer to an int while i1 is just an int.
int const j1 = 0, c1 = 2; // Both j1 and c1 are const int.
Czy const int
jest typem bazowym czy złożonym?
Z błędu w drugiej deklaracji powyżej wynika, że jest to typ bazowy. Jeśli tak, to co z pierwszą deklaracją?
Innymi słowy, jeśli pierwsze stwierdzenie jest legalne, dlaczego drugie nie? Również, dlaczego czy zachowanie różni się między trzecim i czwartym stwierdzeniem?2 answers
Dobre pytanie, ze skomplikowaną odpowiedzią. Aby to naprawdę zrozumieć, musisz dość dokładnie zrozumieć wewnętrzną strukturę deklaracji C++.
(zauważ, że w tej odpowiedzi całkowicie pominę istnienie atrybutów, aby zapobiec nadmiernej komplikacji).
Deklaracja składa się z dwóch elementów: sekwencji specyfikacji, {[65] } , po której następuje oddzielona przecinkami lista INIT-deklaratorów.
Specyfikatorami są:
- przechowywanie specyfikatory klas (np.
static
,extern
) - specyfikatory funkcji (np.
virtual
,inline
) -
friend
,typedef
,constexpr
-
Typ specyfikacji , które obejmują:
- specyfikatory prostych typów (np.
int
,short
) -
CV-kwalifikatory (
const
,volatile
) - inne rzeczy (np.
decltype
)
- specyfikatory prostych typów (np.
Druga część deklaracji to oddzielone przecinkami deklaratory init. Każdy INIT-deklarator składa się z ciągu declarators, opcjonalnie następuje inicjalizator .
Czym są deklaracje:
- identyfikator (np.
i
wint i;
) - operatory podobne do wskaźników (
*
,&
,&&
, składnia pointer-to-member) - składnia parametru funkcji (np.
(int, char)
) - składnia tablicy (np.
[2][3]
) - CV-qualifiers , jeśli te następują po wskaźniku deklaratora.
Zauważ, że struktura deklaracji jest ścisła: najpierw specyfikatory, potem INIT-deklarators (każdy z nich jest deklarators opcjonalnie, a następnie inicjalizator).
Reguła jest następująca: specyfikatory mają zastosowanie do całej deklaracji, podczas gdy deklaratory mają zastosowanie tylko do jednego INIT-deklaratora (do jednego elementu listy rozdzielonej przecinkami).
Zwróć również uwagę powyżej, że kwalifikator cv może być używany zarówno jako specyfikator, jak i deklarator. Jako deklaratoria gramatyka ogranicza je do użycia tylko w obecności wskaźników.
Więc, aby obsłużyć cztery zamieszczone przez Ciebie deklaracje:
1
int i = 0, *const p = &i;
Część specifier zawiera tylko jeden specifier: int
. Jest to część, do której będą stosować się wszyscy zgłaszający.
Istnieją dwa INIT-deklaratory: i = 0
i * const p = &i
.
i
i inicjalizator = 0
. Ponieważ nie ma deklaracji modyfikującej typ, typ i
jest podawany przez specyfikatory, int
w tym przypadku.
Drugi INIT-deklarator ma trzy zgłaszający / a: *
, const
, i p
. I inicjalizatora, = &i
.
Deklaratory *
i const
zmieniają typ bazowy na " stały wskaźnik do typu bazowego."Typ bazowy, podany przez specyfikatorów, to int
, do typu p
będzie" stałym wskaźnikiem do int
."
2
int j = 0, const c = 2;
Ponownie jeden specyfikator: int
i dwa INIT-deklaratory: j = 0
i const c = 2
.
Dla drugiego INIT-declaratora, deklaraatorami są const
i c
. As I wspomniane, gramatyka dopuszcza CV-qualifiers jako deklaratory tylko wtedy, gdy występuje wskaźnik. Tutaj tak nie jest, stąd ten błąd.
3
int *const p1 = nullptr, i1 = 0;
Jeden specifier: int
, dwa INIT-deklaratory: * const p1 = nullptr
i i1 = 0
.
Dla pierwszego INIT-declarator, deklaratory są: *
, const
, i p1
. Mamy już do czynienia z takim INIT-deklarator (drugi w przypadku 1). Dodaje "stały wskaźnik do typu bazowego" do określonego typu bazowego (który jest nadal int
).
Dla drugiego INIT-deklaratora i1 = 0
, to oczywiste. Brak modyfikacji typu, użyj specyfikatorów w stanie, w jakim są. Więc i1
staje się int
.
4
int const j1 = 0, c1 = 2;
Tutaj Mamy zasadniczo inną sytuację niż poprzednie trzy. Mamy dwa specyfikatory: int
i const
. A następnie dwa INIT-deklaratory, j1 = 0
i c1 = 2
.
Żaden z tych INIT-deklaratorów nie ma w sobie żadnych deklaracji modyfikujących Typ, więc oba używają typu z specyfikatorów, czyli const int
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-09 10:44:27
Jest to określone w [dcl.dcl] i [dcl.decl] jako część simple-declaration
* i sprowadza się do różnic między gałęziami w ptr-declarator
:
declaration-seq: declaration declaration: block-declaration block-declaration: simple-declaration simple-declaration: decl-specifier-seqopt init-declarator-listopt ; ---- decl-specifier-seq: decl-specifier decl-specifier-seq decl-specifier: type-specifier ← mentioned in your error type-specifier: trailing-type-specifier trailing-type-specifier: simple-type-specifier cv-qualifier ---- init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator initializeropt declarator: ptr-declarator ptr-declarator: ← here is the "switch" noptr-declarator ptr-operator ptr-declarator ptr-operator: ← allows const * cv-qualifier-seq opt cv-qualifier: const volatile noptr-declarator: ← does not allow const declarator-id declarator-id: id-expression
Ważny widelec w regulaminie jest w ptr-declarator
:
ptr-declarator:
noptr-declarator
ptr-operator ptr-declarator
Zasadniczo, noptr-declarator
w Twoim kontekście jest tylko id-expression
. Nie może zawierać żadnych cv-qualifier
, ale kwalifikowane lub niekwalifikowane identyfikatory. Jednak ptr-operator
może zawierać cv-qualifier
.
To wskazuje, że Twoje pierwsze stwierdzenie jest całkowicie poprawne, ponieważ twoje drugie init-declarator
*const p = &i;
Jest ptr-declarator
postaci ptr-operator ptr-declarator
z ptr-operator
będącą * const
w tym przypadku i ptr-declarator
będącą niekwalifikowanym identyfikatorem.
Twoje drugie oświadczenie nie jest legalne, ponieważ nie jest ważne ptr-operator
:
const c = 2
A ptr-operator
musi zaczynać się od *
, &
, &&
lub zagnieżdżony specyfikator nazwy, po którym następuje *
. Ponieważ const c
nie zaczyna się od żadnego z tych tokenów, uznajemy const c
za noptr-declarator
, co nie pozwala const
tutaj.
Również, dlaczego zachowanie / align = "left" /
Ponieważ int
jest type-specifier
, a *
jest częścią init-declarator
,
*const p1
Deklaruje stały wskaźnik.
Jednak w int const
mamy decl-specifier-seq
dwiedecl-specifier
, int
(a simple-type-specifier
) i const
(a cv-qualifier
), zob. trailing-type-specifier
. Dlatego oba tworzą jedną deklarację.
* Uwaga: pominąłem wszystkie alternatywy, których nie można tutaj zastosować i uprościłem niektóre zasady. Patrz sekcja 7 "deklaracje" oraz sekcja 8 "deklaracje" C++11 (n3337) aby uzyskać więcej informacji.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-09 10:48:44