2011-12-17 13 views
51

Quando uso C++ 11 auto, quali sono le regole di deduzione del tipo per quanto riguarda la risoluzione di un valore o un riferimento?Semantica C++ 11 "auto"

per esempio, a volte è chiaro:

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

Questi sono meno chiari:

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? 

risposta

58

La regola è semplice: è come si dichiara.

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

esempio seguente dimostra:

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

L'output:

value 
reference 
value 
value 
reference 
value 
+5

Si noti che il '// pointer' non è realmente necessario. Inoltre, solo perché un compilatore fornisce questo output non significa che sia conforme allo standard. ;) In questo caso è corretto, sebbene si possa dare una spiegazione migliore di ciò che accade esattamente (il tipo dedotto è "decaduto"). – Xeo

12

§7.1.6.4 [dcl.spec.auto] p6

volta che il tipo di un dichiaratore-id è stato determinare d secondo 8.3, il tipo della variabile dichiarata utilizzando l'identificatore viene determinato dal tipo del relativo inizializzatore utilizzando le regole per la deduzione degli argomenti del modello.

Questo significa nient'altro che la deduzione argomento modello modelli auto durante una chiamata di funzione.

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

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

Nota che # 1 sarà sempre copiare l'argomento passato, non importa se si passa un riferimento o qualsiasi altra cosa. (A meno che non si specifichi specificatamente l'argomento modello come f<int&>(intref);.)

+0

Che cosa significa esattamente questo per i cicli for-based basati sulla distanza? Pensavo volesse dire che sono per riferimento (che a me sembrerebbe logico), ma ho appena scoperto che questo non è accaduto in un caso. – leftaroundabout

+3

@leftaroundabout: non è logico. L '"auto" funziona ugualmente. 'for (auto val: range)' copierà sempre, 'for (auto & ref: range)' sarà sempre un riferimento. E per confondere ancora di più 'for (auto && x: range)' sarà sia 'T &&' o' T &' a seconda che '* begin (range)' restituisca un valore o un riferimento. – Xeo

9

Qualsiasi cosa si ottenga dal lato destro (di "=") non è mai un riferimento. Più in particolare, il risultato di un'espressione non è mai un riferimento. In questa luce, nota la differenza tra i risultati nell'esempio.

#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 
} 
+0

Si prega di includere il resto dell'esempio! Questa è la risposta più succinta ma devi leggerne un'altra per capirla ... – povman

+0

Quella prima frase è proprio quello che stavo cercando. Grazie. –