C ++ 11 "Auto" -Semantik

76

autoWelche Regeln gelten für die Typableitung bei Verwendung von C ++ 11 hinsichtlich der Auflösung in einen Wert oder eine Referenz?

ZB manchmal ist es klar:

auto i = v.begin(); // Copy, begin() returns an iterator by value

Diese sind weniger klar:

const std::shared_ptr<Foo>& get_foo();
auto p = get_foo(); // Copy or reference?

static std::shared_ptr<Foo> s_foo;
auto sp = s_foo; // Copy or reference?

std::vector<std::shared_ptr<Foo>> c;
for (auto foo: c) { // Copy for every loop iteration?
Alex B.
quelle

Antworten:

87

Die Regel ist einfach: So deklarieren Sie sie.

int i = 5;
auto a1 = i;    // value
auto & a2 = i;  // reference

Das nächste Beispiel beweist es:

#include <typeinfo>
#include <iostream>    

template< typename T >
struct A
{
    static void foo(){ std::cout<< "value" << std::endl; }
};
template< typename T >
struct A< T&>
{
    static void foo(){ std::cout<< "reference" << std::endl; }
};

float& bar()
{
    static float t=5.5;
    return t;
}

int main()
{
    int i = 5;
    int &r = i;

    auto a1 = i;
    auto a2 = r;
    auto a3 = bar();

    A<decltype(i)>::foo();       // value
    A<decltype(r)>::foo();       // reference
    A<decltype(a1)>::foo();      // value
    A<decltype(a2)>::foo();      // value
    A<decltype(bar())>::foo();   // reference
    A<decltype(a3)>::foo();      // value
}

Die Ausgabe:

value
reference
value
value
reference
value
BЈовић
quelle
6
Beachten Sie, dass das // pointernicht wirklich notwendig ist. Nur weil ein Compiler diese Ausgabe liefert, bedeutet dies nicht, dass sie standardkonform ist. ;) In diesem Fall ist es richtig, obwohl eine bessere Erklärung gegeben werden kann, was genau passiert (der abgeleitete Typ ist "verfallen").
Xeo
@Nikos Wiederholung dieser Frage (und Antworten) Jahre später… und es stellt sich heraus, dass es Fälle gibt, in denen der Typ variieren kann: universelle Referenzen . Grundsätzlich werden Deklarationen wie auto&& a = ...und T&& b = ...(in Vorlagen) den l-Wert oder den r-Wert angeben, je nachdem, wofür der Ausdruck ausgewertet wird.
Alex B
14

§7.1.6.4 [dcl.spec.auto] p6

Sobald der Typ einer Deklarator-ID gemäß 8.3 bestimmt wurde, wird der Typ der deklarierten Variablen unter Verwendung der Deklarator-ID aus dem Typ ihres Initialisierers unter Verwendung der Regeln für die Ableitung von Vorlagenargumenten bestimmt.

Dies bedeutet nichts anderes als das autoModellieren der Ableitung von Vorlagenargumenten während eines Funktionsaufrufs.

template<class T>
void f(T){} // #1, will also be by-value

template<class T>
void g(T&){} // #2, will always be by-reference

Beachten Sie, dass # 1 das übergebene Argument immer kopiert, unabhängig davon, ob Sie eine Referenz oder etwas anderes übergeben. (Es sei denn, Sie geben ausdrücklich das Vorlagenargument wie an f<int&>(intref);.)

Xeo
quelle
Was genau bedeutet dies für bereichsbasierte for-Schleifen? Ich dachte, es bedeutete, dass sie als Referenz dienen (was mir logisch erscheint), entdeckte aber nur, dass dies in einem Fall nicht geschah.
links um den
3
@leftaroundabout: Das ist nicht logisch. Das autodort funktioniert genauso. for(auto val : range)wird immer kopieren, for(auto& ref : range)wird immer eine Referenz sein. Und noch mehr zu verwirren for(auto&& x : range)ist entweder T&&oder T&hängt davon ab, ob *begin(range)ein Wert oder eine Referenz zurückgegeben wird.
Xeo
9

Was auch immer Sie von der rechten Seite (von "=") erhalten, ist niemals eine Referenz. Insbesondere ist das Ergebnis eines Ausdrucks niemals eine Referenz. Beachten Sie in diesem Licht den Unterschied zwischen den Ergebnissen im Beispiel.

#include <typeinfo>
#include <iostream>

template< typename T >
struct A
{
    static void foo(){ std::cout<< "value" << std::endl; }
};

template< typename T >
struct A< T&>
{
    static void foo(){ std::cout<< "reference" << std::endl; }
};

float& bar()
{
    static float t=5.5;
    return t;
}

int main()
{
   auto a3 = bar();

   A<decltype(bar())>::foo(); // reference
   A<decltype(a3)>::foo();    // value
}
qqqqq
quelle
1
Bitte geben Sie den Rest des Beispiels an! Dies ist die prägnanteste Antwort, aber Sie müssen eine andere lesen, um sie zu verstehen ...
Luke Worth
1
Dieser erste Satz ist genau das, wonach ich gesucht habe. Vielen Dank.
Victor Eijkhout