2011-12-17 4 views
51

私はC++ 11 autoを使用し、それが値または参照に解決されるかどうかに関してで型推論のルールは何ですか?C++ 11「オート」の意味

例えば、時にはそれがクリアされている:

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

これらはそれほど明確である:

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? 

答えて

58

ルールは単純です:それはあなたがそれを宣言する方法です。

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

次の例では、それを証明:

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

出力:

value 
reference 
value 
value 
reference 
value 
+5

「//ポインタ」は実際には必要ないことに注意してください。また、1つのコンパイラがこの出力を出すだけで、それが標準に準拠しているとは限りません。 ;)この場合正しいですが、正確に何が起こったのかをよりよく説明することができます(推定されるタイプは "減衰"しています)。 – Xeo

12

§7.1.6.4 [dcl.spec.auto] p6

宣言子-IDのタイプが決定されたら8.3に従って、宣言子IDを使用して宣言された変数の型は、テンプレート引数の控除の規則を使用して初期化子の型から決定されます。

これは、関数呼び出し時にそのautoモデルテンプレート引数控除よりも何もないことを意味します。

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

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

#1は、参照やその他のものを渡しても、渡された引数を常にコピーすることに注意してください。 (あなたは、具体的f<int&>(intref);のようなテンプレート引数を指定しない限り。)

+0

これは、範囲ベースのfor-loopsとはどういう意味ですか?私はそれが(私に論理的に見える)参照であることを意味しましたが、これが1つのケースでは起こらなかったことを発見しました。 – leftaroundabout

+3

@leftaroundabout:これは論理的ではありません。 'auto'はまったく同じ働きをします。 'for(auto val:range)'は常にコピーされ、for(auto&ref:range)は常に参照になります。混乱させるために 'for(auto && x:range)'は '* begin(range)'が値または参照を返すかどうかによって 'T &&'または 'T&'のいずれかになります。 – Xeo

9

あなたが(「=」の)右側から得るものは何でも参照になることはありません。より具体的に言えば、式の結果は決して参照ではありません。この点で、この例の結果の違いに注意してください。

#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

残りの例を含めてください!これは最も簡潔な答えですが、あなたはそれを理解するために別のものを読む必要があります... – povman

+0

最初の文は私が探していたものです。ありがとう。 –