C ++ 11 auto: Was ist, wenn es eine konstante Referenz erhält?

73

Bitte schauen Sie sich den folgenden einfachen Code an:

class Foo
{
public:
  Foo(){}
  ~Foo(){}

  Foo(const Foo&){}
  Foo& operator=(const Foo&) { return *this; }
};

static Foo g_temp;
const Foo& GetFoo() { return g_temp; }

Ich habe versucht, so zu verwenden auto:

auto my_foo = GetFoo();

Ich habe erwartet, dass my_foodies ein konstanter Verweis auf Fooden Rückgabetyp der Funktion sein wird. Die Art von autoist jedoch Foonicht die Referenz. Darüber hinaus my_foowird durch Kopieren erstellt g_temp. Dieses Verhalten ist für mich nicht so offensichtlich.

Um den Verweis auf zu bekommen Foo, musste ich so schreiben:

const auto& my_foo2 = GetFoo();
      auto& my_foo3 = GetFoo();

Frage : Warum wird autoder Rückgabetyp GetFooals Objekt und nicht als Referenz abgeleitet?

Minjang
quelle
VC ++ 2010 und Intel C ++ Compiler
Minjang

Antworten:

62

Lesen Sie diesen Artikel: Anzeigen und Verschwinden von Konstanten in C ++


Der Typabzug für automatische Variablen in C ++ 0x ist im Wesentlichen der gleiche wie für Vorlagenparameter. (Soweit ich weiß, besteht der einzige Unterschied zwischen den beiden darin, dass der Typ der automatischen Variablen möglicherweise aus Initialisierungslisten abgeleitet wird, während der Typ der Vorlagenparameter möglicherweise nicht abgeleitet wird.) Jede der folgenden Deklarationen deklariert daher Variablen vom Typ int ( nie const int):

auto a1 = i;
auto a2 = ci;
auto a3 = *pci;
auto a4 = pcs->i;

Während des Typabzugs für Vorlagenparameter und automatische Variablen werden nur Konstanten der obersten Ebene entfernt. Bei einer Funktionsvorlage, die einen Zeiger oder Referenzparameter verwendet, bleibt die Konstanz dessen, worauf gezeigt oder verwiesen wird, erhalten:

template<typename T>
void f(T& p);

int i;
const int ci = 0;
const int *pci = &i;

f(i);               // as before, calls f<int>, i.e., T is int
f(ci);              // now calls f<const int>, i.e., T is const int
f(*pci);            // also calls f<const int>, i.e., T is const int

Dieses Verhalten ist eine alte Nachricht und gilt sowohl für C ++ 98 als auch für C ++ 03. Das entsprechende Verhalten für automatische Variablen ist natürlich neu in C ++ 0x:

auto& a1 = i;       // a1 is of type int&
auto& a2 = ci;      // a2 is of type const int&
auto& a3 = *pci;    // a3 is also of type const int&
auto& a4 = pcs->i;  // a4 is of type const int&, too

Da Sie das cv-Qualifikationsmerkmal beibehalten können, wenn der Typ eine Referenz oder ein Zeiger ist, können Sie Folgendes tun:

auto& my_foo2 = GetFoo();

Anstatt es angeben zu müssen als const(dasselbe gilt für volatile).

Bearbeiten: Beachten Sie autoFolgendes, warum der Rückgabetyp GetFoo()als Wert anstelle einer Referenz abgeleitet wird (was leider Ihre Hauptfrage war):

const Foo my_foo = GetFoo();

Das obige erstellt eine Kopie, da my_fooes sich um einen Wert handelt. Wenn autoeine Wertreferenz zurückgegeben würde, wäre dies nicht möglich.

irgendein Typ
quelle
9
Sie haben nicht erklärt, warum auch das Ref-Qualifikationsmerkmal entfernt wird.
Leichtigkeitsrennen im Orbit
3
@Tomalak Geret'kal: Du meinst, warum sie sich dazu entschlossen haben? Es macht Sinn, nicht wahr? Bedenken Sie Folgendes: Foo my_foo = GetFoo();und das GetFoo()hat keinen const-Typ zurückgegeben. Es wäre das gleiche wie : auto my_foo = GetFoo();. Wenn auto auch die Referenz enthält, können Sie die oben genannten Schritte nicht ausführen.
Irgendwann
6
Sag es mir nicht; Gib es in deine Antwort ein.
Leichtigkeitsrennen im Orbit
1
Scott Meyers, Buch Effective Modern C ++, widmet ein ganzes Kapitel, um dies zu erklären. Muss man lesen.
Dehinrsu