Заменители типов спецификаторов (с C++11)
Для переменных, указывает, что тип переменной, которая объявляется, будет автоматически выведен из её инициализатора.
| Для функций, указывает, что возвращаемый тип будет выведен из её операторов возврата. | (с C++14) |
| Для нетиповых параметров шаблонов, указывает, что тип будет выведен из аргумента. | (с C++17) |
Синтаксис
ограничение типа (необязательно) auto | (1) | (с C++11) |
ограничение типа (необязательно) decltype ( auto ) | (2) | (с C++14) |
| ограничение типа | - | (с C++20) имя концепции, необязательно с квалификатором, необязательно с последующим списком аргументов шаблона, заключённым в <> |
decltype(expr), где expr — это инициализатор или используемые в операторах возврата.Заполнитель auto может сопровождаться модификаторами, такими как const или &, которые будут участвовать в выводе типа. Заполнитель decltype(auto) должен быть единственным элементом объявленного типа.(с C++14)
Объяснение
Заполнитель типа может появляться в следующих контекстах:
- в последовательности спецификаторов типа переменной:
auto x = expr;как спецификатор типа. Тип выводится из инициализатора.
Если заполнитель типа —autoили ограничение типаauto(с C++20), тип переменной выводится из инициализатора по правилам вывода аргументов шаблона из вызова функции (см. вывод аргументов шаблона — другие контексты для деталей).
Например, приconst auto& i = expr;, типi— это точно тип аргументаuв воображаемом шаблонеtemplate<class U> void f(const U& u), если вызов функцииf(expr)был скомпилирован. Поэтомуauto&&может быть выведен как ссылка на lvalue или rvalue ссылку в соответствии с инициализатором, который используется в цикле for, основанном на диапазоне.
Если заполнитель типа —
decltype(auto)или ограничение типаdecltype(auto)(с C++20), выведенный тип —decltype(expr), гдеexpr— инициализатор.(с C++14) Если заполнитель типа используется для объявления нескольких переменных, выведенные типы должны совпадать. Например, объявление
auto i = 0, d = 0.0;некорректно, а объявлениеauto i = 0, *p = &i;корректно, иautoвыводится какint. - в type-id выражения new. Тип выводится из инициализатора. Для
new T init(гдеTсодержит заполнитель типа, init — это либо инициализатор в скобках, либо список инициализаторов в фигурных скобках), типTвыводится так же, как для переменнойxв выдуманном объявленииT x init;. - (с C++14) в возвращаемом типе функции или лямбда-выражения:
auto& f();. Возвращаемый тип выводится из операнда его не-отбрасываемого(с C++17) оператора return.
См. функция — вывод возвращаемого типа. - (с C++17) в объявлении параметра нетипового параметра шаблона:
template<auto I> struct A;. Его тип выводится из соответствующего аргумента.
| Запись | (с C++23) |
| Кроме того,
| (с C++14) |
Ограничение типаЕсли ограничение типа присутствует, пусть
Вывод терпит неудачу, если выражение ограничения некорректно или возвращает | (с C++20) |
Примечания
До C++11 auto имел семантику спецификатора длительности хранения.
Смешивание auto переменных и функций в одном объявлении, как в auto f() -> int, i = 0; не допускается.
Заполнитель auto может также использоваться с функцией-декларатором, за которым следует возвращаемый тип, в этом случае объявленный возвращаемый тип — это тот возвращаемый тип (который снова может быть заполнителем типа).
auto (*p)() -> int; // declares p as pointer to function returning int
auto (*q)() -> auto = p; // declares q as pointer to function returning T
// where T is deduced from the type of p| Заполнитель | (с C++17) |
| Ключевое слово | (концепции TS) |
| Макрос проверки возможностей | Значение | Std | Функция |
|---|---|---|---|
__cpp_decltype_auto | 201304L | (C++14) |
decltype(auto) |
Пример
#include <iostream>
#include <utility>
template<class T, class U>
auto add(T t, U u) { return t + u; } // the return type is the type of operator+(T, U)
// perfect forwarding of a function call must use decltype(auto)
// in case the function it calls returns by reference
template<class F, class... Args>
decltype(auto) PerfectForward(F fun, Args&&... args)
{
return fun(std::forward<Args>(args)...);
}
template<auto n> // C++17 auto parameter declaration
auto f() -> std::pair<decltype(n), decltype(n)> // auto can't deduce from brace-init-list
{
return {n, n};
}
int main()
{
auto a = 1 + 2; // type of a is int
auto b = add(1, 1.2); // type of b is double
static_assert(std::is_same_v<decltype(a), int>);
static_assert(std::is_same_v<decltype(b), double>);
auto c0 = a; // type of c0 is int, holding a copy of a
decltype(auto) c1 = a; // type of c1 is int, holding a copy of a
decltype(auto) c2 = (a); // type of c2 is int&, an alias of a
std::cout << "before modification through c2, a = " << a << '\n';
++c2;
std::cout << " after modification through c2, a = " << a << '\n';
auto [v, w] = f<0>(); //structured binding declaration
auto d = {1, 2}; // OK: type of d is std::initializer_list<int>
auto n = {5}; // OK: type of n is std::initializer_list<int>
// auto e{1, 2}; // Error as of DR n3922, std::initializer_list<int> before
auto m{5}; // OK: type of m is int as of DR n3922, initializer_list<int> before
// decltype(auto) z = { 1, 2 } // Error: {1, 2} is not an expression
// auto is commonly used for unnamed types such as the types of lambda expressions
auto lambda = [](int x) { return x + 3; };
// auto int x; // valid C++98, error as of C++11
// auto x; // valid C, error in C++
[](...){}(c0, c1, v, w, d, n, m, lambda); // suppresses "unused variable" warnings
}Возможный вывод:
before modification through c2, a = 3 after modification through c2, a = 4
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющих поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применяется к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| CWG 1265 | C++11 | спецификатор auto мог использоваться для объявления функции с возвращаемым типом в конце и определения переменной в одном операторе объявления | запрещено |
| CWG 1346 | C++11 | список выражений в скобках не мог быть присвоен переменной типа auto | разрешено |
| CWG 1347 | C++11 | объявление со спецификатором auto могло определить две переменныес типами T и std::initializer_list<T> соответственно | запрещено |
| CWG 1852 | C++14 | спецификатор auto в decltype(auto) также был плейсхолдером | не является плейсхолдером в данном случае |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/language/auto