C ++ 11 auto: что если он получает постоянную ссылку? - PullRequest
69 голосов
/ 21 августа 2011

Пожалуйста, взгляните на следующий простой код:

class Foo
{
public:
  Foo(){}
  ~Foo(){}

  Foo(const Foo&){}
  Foo& operator=(const Foo&) { return *this; }
};

static Foo g_temp;
const Foo& GetFoo() { return g_temp; }

Я пытался использовать auto так:

auto my_foo = GetFoo();

Я ожидал, что my_foo будет постоянной ссылкой на Foo, который является типом возврата функции. Однако тип auto - это Foo, а не ссылка. Кроме того, my_foo создается путем копирования g_temp. Такое поведение не так очевидно для меня.

Чтобы получить ссылку на Foo, мне нужно было написать так:

const auto& my_foo2 = GetFoo();
      auto& my_foo3 = GetFoo();

Вопрос : Почему auto выводит тип возвращаемого значения GetFoo как объект, а не как ссылку?

1 Ответ

61 голосов
/ 21 августа 2011

Прочитайте эту статью: Появление и исчезновение констант в C ++


Вывод типа для авто переменных в C ++ 0x по сути такой же, как для параметров шаблона. (Насколько я знаю, единственная разница между ними то, что тип авто переменных может быть выведен из списки инициализатора, в то время как типы параметров шаблона могут не быть.) Поэтому каждое из следующих объявлений объявляет переменные типа int (никогда не const int):

auto a1 = i;
auto a2 = ci;
auto a3 = *pci;
auto a4 = pcs->i;

Только при выводе типа для параметров шаблона и автоматических переменных констант верхнего уровня удаляются. Учитывая шаблон функции, принимающий указатель или ссылочный параметр, постоянство чего бы то ни было указано или ссылка сохраняется:

template<typename T>
void f(T& p);

int i;
const int ci = 0;
const int *pci = &i;

f(i);               // as before, calls f<int>, i.e., T is int
f(ci);              // now calls f<const int>, i.e., T is const int
f(*pci);            // also calls f<const int>, i.e., T is const int

Такое поведение - старые новости, которые применяются как к C ++ 98, так и к C ++ 03. Соответствующее поведение для автоматических переменных, конечно, новичок в C ++ 0x:

auto& a1 = i;       // a1 is of type int&
auto& a2 = ci;      // a2 is of type const int&
auto& a3 = *pci;    // a3 is also of type const int&
auto& a4 = pcs->i;  // a4 is of type const int&, too

Поскольку вы можете сохранить квалификатор cv, если тип является ссылкой или указателем, вы можете сделать:

auto& my_foo2 = GetFoo();

Вместо того, чтобы указывать его как const (то же самое относится и к volatile).

Редактировать: Что касается того, почему auto выводит тип возвращаемого значения GetFoo() в качестве значения вместо ссылки (что было вашим главным вопросом, извините), учтите следующее:

const Foo my_foo = GetFoo();

Приведенное выше создаст копию, поскольку my_foo является значением. Если бы auto вернул ссылку на lvalue, вышеприведенное было бы невозможно.

...