С++ 11 "авто" семантика
Когда я использую С++ 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?
Ответы
Ответ 1
Правило простое: это как вы его объявляете.
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
Ответ 2
§7.1.6.4 [dcl.spec.auto] p6
Как только тип идентификатора-декларатора был определен в соответствии с 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);
.)
Ответ 3
Все, что вы получаете с правой стороны (от "=" ), никогда не является ссылкой. Более конкретно, результат выражения никогда не является ссылкой. В этом свете обратите внимание на разницу между результатами в этом примере.
#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
}