C ++ 11“自动”语义


76

当我使用C ++ 11时auto,关于类型演绎将解析为值还是引用的规则是什么?

例如,有时很明显:

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?

Answers:


87

规则很简单:这就是您声明的方式。

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

6
请注意,这// pointer并不是真正必要的。同样,仅因为一个编译器提供此输出并不意味着它符合标准。;)在这种情况下是正确的,尽管可以给出确切的解释(推导的类型为“衰减的”)。
Xeo

@Nikos几年后重温了这个问题(和答案)……结果发现在某些情况下类型可能会有所不同:通用引用。基本上,像auto&& a = ...和这样的声明T&& b = ...(在模板中)将是左值或右值,这取决于表达式的计算结果。
亚历克斯B

14

§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);。)


那么这对于基于范围的for循环到底意味着什么呢?我虽然表示它们是按引用的(对我来说似乎是合逻辑的),但是我发现这在一种情况下没有发生。
大约

3
@leftaroundabout:这是不合逻辑的。在auto那里工作得一样。for(auto val : range)将始终复制,for(auto& ref : range)将始终作为参考。而迷惑更加for(auto&& x : range)要么是T&&还是T&取决于是否*begin(range)会返回一个值或引用。
Xeo 2012年

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
}

1
请包括其余示例!这是最简洁的答案,但您需要阅读另一个才能理解它……
卢克·沃思2014年

1
那第一句话正是我所要的。谢谢。
Victor Eijkhout,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.