Pytanie Typ (x) w C ++ [duplikat]


To pytanie już zawiera odpowiedź:

  • dekltype i nawiasy                     3 odpowiedzi                 

Dany:

decltype(auto) f1()
{
    int x = 0;
    return x;  // decltype(x) is int, so f1 returns int
}
decltype(auto) f2()
{
    int x = 0;
    return (x);  // decltype((x)) is int&, so f2 returns int&
}

(Zaczerpnięte z Efektywnego Nowoczesnego C ++ Scotta Meyera).

Teraz, jeśli znalazłem właściwy akapit, Sekcja 7.1.5.2 Proste specyfikatory typów [dcl.type.simple] standardu C ++ mówi:

Jeśli e jest wyrażeniem id lub członkiem klasy (5.2.5 [wyrażenie.ref]),   decltype (e) jest zdefiniowany jako typ podmiotu określonego przez e

a przykład z tej sekcji to:

struct A { double x; }

const A* a = new A();

decltype((a->x)); // type is const double&

Teraz zastanawiam się, dlaczego jest decltype((x)) jest wydedukowany int& w książce.


21
2017-11-02 14:13


pochodzenie


dlaczego potrzebujesz tego typu decltype? auto wystarczy ... - David Haim
ale spójrzmy prawdzie w oczy, odpowiedzią prawdopodobnie będzie ktoś cytujący ze standardu jakiś dziwaczny neuance jakiejś ezoterycznej reguły, która sprawia, że ​​zachowuje się jak ona ... - David Haim
@DavidHaim dodał tag dla dziwnych niuansów niuansów zasad ezoterycznych. - Quentin
@DavidHaim Chociaż to, co opisujesz, zdarza się często na tej stronie, nie nazwałbym tego zupełnie nieszablonowym zastosowaniem zaawansowanego C ++ 11 z "dziwaczną nigdzie jakiejś ezoterycznej zasady". - Baum mit Augen
Widzieć dekltype i nawiasy - Shafik Yaghmour


Odpowiedzi:


Odpowiedni standard to:

N4140 [dcl.type.simple]/4: Do wyrażenia e, typ oznaczony przez decltype(e) jest zdefiniowany w następujący sposób:

  • jeśli e jest nieprecyzyjnym id-wyrażeniem lub niepasteryzowanym dostępem do klasy (5.2.5), decltype(e)   jest typem jednostki nazwanej przez e. Jeśli nie ma takiego bytu lub jeśli podaje zestaw nadmiernie obciążonych funkcji, program jest źle sformułowany;
  • inaczej, jeśli e jest xvalue, decltype(e) jest T&&, gdzie T jest typem e;
  • inaczej, jeśli e jest lwartością, decltype(e) jest T&, gdzie T jest typem e;
  • Inaczej, decltype(e) jest typem e.

Od x jest wartością l, a wyrażenie jest nawiasie, trzecia reguła jest używana, więc decltype((x)) jest int&.


10
2017-11-02 14:39





decltype zwraca zadeklarowany typ zmiennej lub "typ" wyrażenia (z pewnym odniesieniem dodanym w celu wskazania wartości l / r).

Pozwala to na wykorzystanie go do dwóch różnych celów. Czasami powoduje to zamieszanie, ale tak właśnie jest.

Token x jest zmienną. Typ zmiennej to int.

Żetony (x) są nie zmienna, ale raczej (naprawdę trywialne) wyrażenie zawierające tylko jedną zmienną. Jako taki, typ wyrażenie (jak określono przez decltype) (x) jest int&.

Typ wyrażenia x (jeśli możesz przekonać decltype, by ci go dał, nie możesz) to także int&, ale zasada, że decltype(ACTUAL_VAR_NAME) ocenia na typ zmiennej "wygrywa".

Teraz żadna z powyższych nie jest prawdziwa. Prawdziwa prawda jest cytatem standardu, który opisuje kroki, które powinien wykonać kompilator, aby określić, jaki typ decltype zwraca. Ale jest to skuteczne kłamstwo, a jedno (jeśli standardowe sformułowanie okazało się mieć błędy), które może wskazywać, że standard ma błąd, gdy się z nim nie zgadza.


8
2017-11-02 14:41





§ 7.1.6.4 [dcl.spec.auto] (projekt n3797)

  1. ... Jeśli zastępczy jest   decltype (auto)   specyfikator typu   , zadeklarowany typ zmiennej lub typ zwrotu   Funkcja jest jedynie symbolem zastępczym. Określany jest typ wydedukowany dla zmiennej lub typu powrotu   jak opisano w   7.1.6.2   , jakby inicjator był operandem   decltype   .

§ 7.1.6.2 [dcl.type.simple]

  1. Do wyrażenia   mi   , typ oznaczony przez   decltype (e)   jest zdefiniowany w następujący sposób:

-    gdyby   mi   jest niepasteryzowane   id-expression   lub niepasteryzowany dostęp do członków klasy (   5.2.5   ),   decltype (e)   jest typem jednostki nazwanej przez   mi   . Jeśli nie ma takiego bytu lub jeśli   mi   wymienia zestaw przeciążonych funkcji   że program jest źle sformułowany;

-    inaczej, jeśli   mi   jest xvalue,   decltype (e)   jest   T &&   , gdzie   T   jest typem   mi   ;

-    inaczej, jeśli   mi   jest lwartością,   decltype (e)   jest   T &   , gdzie   T   jest typem   mi   ;

-    Inaczej,   decltype (e)   jest typem   mi

x is jest niepreatyfikowanym id-wyrażeniem, a zatem typ zwracany jest wydedukowany jako typ x: int

(x) jest nie na unparenthesized id-expression, więc ta reguła nie ma zastosowania. Jednakże to jest a (parentetyzowana) wartość wyrażenia l. Dlatego też typem dedukcyjnym jest T& gdzie T jest typem x: int&


5
2017-11-02 14:38



@downvoter jest błąd w odpowiedzi? Jak mogę to poprawić? - user2079303


[dcl.spec.auto] / 7 upoważnia, że, w przybliżeniu, typ zwrotu jest uzyskiwany przez zastosowanie decltype do wyrażenia w return komunikat. Tak więc, jak sugeruje komentarz, szukamy decltype((x)). Dziwna reguła wchodzi w:

enter image description here

Pamiętaj, że pierwszy punkt wypunktowania nie ma zastosowania od czasu wyrażenia jest parentetyzowany. Dlatego otrzymujemy int&.


To rozróżnienie między aplikacjami decltype na prostych identyfikatorach i nawiasach wprowadzono wersję 6 odpowiedniego papieru. Widzieć w wersja 5, §2.3:

Typ oznaczony przez decltype(e) jest zdefiniowany w następujący sposób:

  1. Gdyby e jest w formie (e1), decltype(e) jest zdefiniowany jako decltype(e1).

Uzasadnieniem tego jest prawdopodobnie: Pisanie (x), programista zamierza decltype nie traktować operandu jako nazwy, ale raczej wyrażenie - biorąc pod uwagę jego kategorię wartości.


5
2017-11-02 14:40





Jak już zaznaczył @Cumbobo, (a-> x) należy traktować jako wyrażenie i to wyrażenie jest  const kwalifikowany, ponieważ * a jest const.

Rozważmy to

decltype((a->x)); 

nie był const wykwalifikowany.

Następnie np. to

decltype((a->x)) ref = (a->x); 

będzie domyślnie sortować - podnieść kwalifikator * a const, ponieważ * a's x może zostać zmienione przez ref.


0
2017-11-02 15:16