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

Обратите внимание, что '// указатель' на самом деле не нужен. Кроме того, только потому, что один компилятор дает этот вывод, это не значит, что он соответствует стандарту. ;) В этом случае это правильно, хотя может быть дано лучшее объяснение, что именно происходит (выведенный тип «затухает»). – Xeo

12

§7.1.6.4 [dcl.spec.auto] p6

После того типа описатель-ID было определить, d согласно 8.3, тип объявленной переменной с использованием идентификатора объявления определяется по типу его инициализатора, используя правила для вычитания аргумента шаблона.

Это не что иное, как то, что 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

Так что же это значит для диапазонов для циклов? Я имею в виду, что они являются ссылочными (что может показаться мне логичным), но только что обнаружили, что этого не произошло в одном случае. – leftaroundabout

+3

@leftaroundabout: Это не логично. «Авто» работает одинаково. 'for (auto val: range)' всегда будет копировать, 'для (auto & ref: range)' всегда будет ссылкой. И чтобы запутать еще больше 'for (auto && x: range)' будет либо 'T &&', либо 'T &' в зависимости от того, будет ли '* begin (range)' возвращать значение или ссылку. – 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

Это первое предложение именно то, что я искал. Благодарю. –

Смежные вопросы