2011-12-17 110 views
51

当我使用C++ 11 auto时,关于是否将解析为值或引用的类型推导规则是什么?C++ 11“auto”semantics

E.g,有时是明确的:

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

请注意,//指针并不是真的必要。另外,仅仅因为一个编译器给出这个输出并不意味着它符合标准。 ;)在这种情况下,它是正确的,尽管可以给出更准确的解释(推导的类型是“衰减的”)。 – Xeo 2011-12-17 11:22:38

12

§7.1.6.4 [dcl.spec.auto] p6

一旦说明符-ID的类型已经确定d根据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循环意味着什么呢?虽然这意味着它们是通过引用(这对我来说似乎合乎逻辑),但是只是发现这种情况在一种情况下不会发生。 – leftaroundabout 2012-01-29 21:55:18

+3

@leftaroundabout:这不合逻辑。那里的`auto'也是一样的。 `for(auto val:range)`将始终复制,`for(auto&ref:range)`始终是引用。并且,根据'* begin(range)`是否会返回一个值或一个引用,'for(auto && x:range)'会更多地混淆`T &&`或`T&`。 – Xeo 2012-01-29 22:29:02

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 
}