decltype für die Variable des Referenztyps mit geschweiften Klammern
Betrachten Sie den folgenden Code :
#include <type_traits>
int main() {
const int& p = 42;
auto v1 = decltype(p){};
static_assert(std::is_same_v<decltype(v1), int>);
decltype(p) v2{};
static_assert(std::is_same_v<decltype(v2), const int&>);
// auto v3 = X(const int&)X {};
}
Art von v1
wird abgeleitet als int
. Gleichzeitig wird der Typ von v2
voraussichtlich als abgeleitet const int&
. Ich denke, der erste Schritt für v1
könnte so behandelt werden, dass ein weiterer Typ-Alias hinzugefügt wird using T = decltype(p);
und dann auto v4 = T{};
. Wie wird dieser Ausdruck ( decltype(p){}
oder T{}
) vom Compiler behandelt? Ich weiß, dass dieser {}
Teil zur Instanziierung dient, aber wie ist der resultierende Typ von v1
kein Referenztyp?
Noch eine Frage: Gibt es eine Möglichkeit, v3
Variablen desselben Typs zu deklarieren , die v1
explizit notierten Typ const int&
(anstelle von decltype(p)
) verwenden?
Alle Links zu Standard wäre dankbar.
Antworten
(An die Downvoter: Wenn Sie downvotiert haben, weil Sie denken, dass das Zitieren von Scott Meyers nicht gleichbedeutend mit dem Zitieren des Standards ist, na ja ...)
Wie Sie aus Effective Modern C ++ lesen können (ergänzt durch den Teil der Errata , den Sie durch Suchen Case 2:
unter diesem Link erreichen können, und das vereinfacht das Lesen nur, ist aber für die Frage nicht wesentlich):
Wenn
ParamType
es sich um eine [...] Nichtreferenz handeltexpr
, wenn der Typ eine Referenz ist, ignorieren Sie den Referenzteil. Wenn [...],expr
ist dasconst
auch wichtig. Wennvolatile
ja, ignorieren Sie das auch.
Wo param
ist der Deklarationsspezifizierer, der in Ihrem Fall gerecht ist auto
, dh eine Nichtreferenz.
Mit anderen Worten, Sie erstellen v1
über Plain auto
(nicht auto&
), dh per Kopie. Es spielt also keine Rolle, ob Sie es mit einer Entität initialisieren, die referenziert ist oder nicht, oder sogar mit const
oder nicht (oder volatile
oder nicht, fwiw). weil du es kopierst.
Denken Sie an den einfacheren Fall,
int i = 3;
int& p = i;
auto v1 = p;
Für ihn v1
ist es wirklich nicht wichtig, ob er mit dem einen ( i
) oder dem anderen ( p
) Namen initialisiert ist, unter dem dieselbe Entität bekannt ist, da er eine Kopie des Wertes erhält, den diese Entität hat.
auto
Der Typabzug funktioniert genauso wie der Typabzug von Vorlagen (mit Ausnahme eines Unterschieds im Umgang mit dem geschweiften Initialisierer, der in diesem Fall nicht relevant ist), und für beide können Sie sich auf Scott Meyers ' Effective Modern C ++ beziehen .