2016-06-30 22 views
10

Ich habe nur eine ähnliche Frage gestellt, die auf dieses Problem hinausläuft.Warum Elementvariablen eines const Objekts nicht const sind

#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; 
} 

Warum die Vorlagen werden nicht const int statt int?

Antwort

9

decltype gibt Ihnen den "deklarierten Typ" des Operanden, wenn er nicht in einem zusätzlichen Satz von Klammern eingeschlossen ist.

Um den tatsächlichen Typ des Ausdrucks zu erhalten, das heißt const int, müssten Sie decltype((a.a)) schreiben und so weiter.

decltype gibt immer einen Referenztyp für andere Lvalue-Ausdrücke als Namen zurück.

+0

Also 'declltype' ** immer ** gibt nur den Typ der Deklaration des Namens zurück, wie im Code definiert? Ignorieren Sie die 'const'ness,' ref'ness oder 'volatile'ness aller Objekte, die dorthin gebracht wurden? zum Beispiel eine Variable innerhalb eines 'const' Objekts? – Curious

+2

@Curious Für den speziellen Fall, dass der Operand nur der Name einer Variablen oder eines Mitgliedszugriffsausdrucks ist, gibt yes den Typ der Deklaration an. Die cv-Qualifizierung des einschließenden Objekts ändert den Typ des Ausdrucks, aber Sie erhalten nur den Typ des Ausdrucks, wenn Sie zusätzliche Klammern verwenden. Ähnliches gilt für die Wertkategorie. – Brian

2

Wenn der Name eines Bezeichners (oder Members) übergeben wird, wird der Typ der Deklaration zurückgegeben.

Wenn ein anderer Ausdruck übergeben wird, gibt er etwas zurück, was näher an dem ist, was Sie wollen, aber referenziert.

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

live example oder wenn Sie die l/r valueness wollen:

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

können Sie anhängen && machen ihn zu einem "echten" rvalue Referenz hier.

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

live example.

+0

Das ist großartig! Ich habe diese Methode in Scott Meyers C++ Buch gesehen, also habe ich nicht einmal darüber nachgedacht, als ich es benutzt habe. Gibt es etwas anderes, was ich über 'declltype' wissen sollte, außer dieser Subtilität? – Curious

+0

Sie können 'std :: declval ()' anstelle von '(const A) {}' – Jarod42

+1

@jarrod sicher verwenden, aber das ist länger! – Yakk