2016-06-30 40 views
10

Appena posta una domanda simile che si riduce a questa.Perché le variabili membro di un oggetto const non sono const

#include <iostream> 
using namespace std; 

struct A { 
    A() : a{1} {}; 
    int a; 
}; 

template <typename Which> 
struct WhichType; 

int main() { 
    const A a; 
    const A& a_ref = a; 
    const A* a_ptr = &a; 
    WhichType<decltype(a.a)> which_obj; // template evaluates to int 
    WhichType<decltype(a_ref.a)> which_ref; // template evaluates to int 
    WhichType<decltype(a_ptr->a)> which_ptr; // template evaluates to int 

    return 0; 
} 

Perché i modelli non diventano const int invece di int?

risposta

9

decltype fornisce il "tipo dichiarato" dell'operando quando non è racchiuso tra parentesi.

Per ottenere il tipo effettivo dell'espressione, ovvero const int, è necessario scrivere decltype((a.a)) e così via.

decltype restituisce sempre un tipo di riferimento per le espressioni lvalue diverse dai nomi.

+0

Quindi 'decltype' ** sempre ** restituisce solo il tipo di dichiarazione del nome come definito nel codice? Ignorando 'const'ness,' ref'ness o 'volatile'ness di tutti gli oggetti presi per arrivarci? per esempio una variabile all'interno di un oggetto 'const'? – Curious

+2

@Curious Per il caso specifico in cui l'operando è solo il nome di una variabile o un'espressione di accesso membro, sì, fornisce il tipo di dichiarazione. La qualifica cv dell'oggetto racchiuso modifica il tipo dell'espressione, ma si ottiene il tipo di espressione solo se si utilizzano parentesi aggiuntive. Una cosa simile vale per la categoria di valore. – Brian

2

Quando viene passato il nome di un identificatore (o membro), restituisce il tipo di dichiarazione.

Quando si passa un'espressione diversa, restituisce qualcosa più vicino a ciò che si desidera, ma con qualifica di riferimento.

WhichType<std::remove_reference_t<decltype((a_ptr->a))>> which_ptr; // template evaluates to const int! 

live example o se si desidera che la L/R valueness:

WhichType<decltype((a_ptr->a))> which_ptr2; // template evaluates to const int& 
WhichType<decltype(((const A){}.a))> which_ptr3; // template evaluates to const int 

è possibile aggiungere && per farne un "vero" rvalue di riferimento qui.

WhichType<decltype(((A){}.a))&&> which_ptr4; // template evaluates to int&&! 

live example.

+0

È grandioso! Ho visto questo metodo usato nel libro C++ di Scott Meyer, quindi non ci ho pensato nemmeno quando lo usavo. C'è qualcos'altro che dovrei sapere su "decltype" oltre a questa sottigliezza? – Curious

+0

Puoi usare 'std :: declval ()' invece di '(const A) {}' – Jarod42

+1

@jarrod sicuro, ma è più lungo! – Yakk