Как определяется тип инициализируемой переменной при использовании ключевого слова auto?
В каких случаях переменная окажется константной, ссылкой, указателем, или всё это в различных комбинациях?
Как повлияют на эти правила дополнительные указания, типа const auto, auto&, const auto& (и ещё наверное аналогичные с указателями, может даже с двойными указателями, и с &&)?
Правила вывода очень похожи на правила для функций вроде template <typename T> void foo(T).
[const] [volatile] auto - никогда не будет ссылкой, никакие cv-квалификаторы (const, volatile) автоматически не добавляются.
Особый случай - если такую переменную инициализировать = {a,b,c} - то тип будет [const] [volatile] std::initializer_list<T>.
[const] [volatile] auto & - cv-квалификаторы добавляются автоматически (кроме случая, когда его инициализируют rvalue - тогда без указания const будет ошибка).
int a = 1;
const int b = 1;
auto &x = a; // int &x
auto &y = b; // const int &y
auto &z = 1; // Ошибка, хотя `const int &z = 1` скомпилировалось бы.
const auto &w = 1; // const int &w
[const] [volatile] auto && - если указан хотя бы один cv-квалификатор, то работает по аналогии с auto &, но для rvalue.
Если cv-квалификаторы не указаны, то работает как forwarding ссылка:
MyClass a = 1;
const MyClass b = 1;
auto &&x = a; // MyClass &x
auto &&x = b; // const MyClass &x
auto &&x = MyClass(); // MyClass &&x
auto &&x = (const MyClass) MyClass(); // const MyClass &&x
[const] [volatile] auto &&, так же как и auto, умеет работать с initializer_list:
auto &&x = {1,2,3}; // std::initializer_list<int> &&
Во всех случаях выше, если переменную инициализировать {a} (без =), то auto ведет себя так же, как если бы инициализатор был = a. В фигурных скобках должен быть только один элемент.
auto может упоминаться в более сложных конструкциях: можно делать указатели на auto, указатели-на-члены, и ссылки на них. Разрешаются указатели на указатели, указатели на функции, и т.д. Но массивы с auto почему-то нельзя делать.
Если сделать указатель на auto, то cv-квалификаторы добавляются автоматически:
const int x = 1;
auto *y = &x; // const int *y
Есть еще decltype(auto). Он похож на auto, но на него нельзя формировать ссылки и указатели, и нельзя указывать cv-квалификаторы.
Он использует те же правила вывода, что и decltype.
Он особенно хорошо подходит для написания оберток для функций:
decltype(auto) foo(бла бла)
{
return bar(бла бла);
}
Здесь возвращаемый тип bar копируется в foo, даже если это ссылка.
const int n = 5;
auto m = n; // int
const int& p = n;
auto q = p; //int
const std::vector<int> v(1);
auto a = v[0]; // int
decltype(a) d ; // int, тип сущности, именованной как d
decltype(v[0]) b = 1; // const int& (возвращаемое значение
// std::vector<int>::operator[](size_type) const)
decltype((a)) ref = a; // int&, так как (a) является lvalue
auto value = ref; //int
++ref; // ошибка
++value; //правильно
Сборка персонального компьютера от Artline: умный выбор для современных пользователей