Спецификаторы-заполнители типа (начиная с C++11)
Спецификатор-заполнитель типа задаёт тип-заполнитель, который будет заменён позднее, обычно посредством вывода типа из инициализатора.
Синтаксис
type-constraint (необязательно) auto | (1) | |
type-constraint (необязательно) decltype(auto) | (2) | (начиная с C++14) |
| type-constraint | - |
(начиная с C++20) имя концепта, возможно, с квалификатором и, возможно, за которым следует список аргументов шаблона, заключённый в <> |
decltype(expr), где expr — это инициализатор или операнды, используемые в операторах return.Заполнитель auto может сопровождаться модификаторами, такими как const или &, которые участвуют в выводе типа. Заполнитель decltype(auto) должен быть единственной составляющей объявленного типа.(начиная с C++14)
| Если присутствует type-constraint, пусть
Вывод завершается неудачей, если выражение-ограничение некорректно или возвращает | (начиная с C++20) |
Пояснение
Спецификатор-заполнитель типа может встречаться в следующих контекстах:
Объявления параметровВ следующих объявлениях параметров тип объявляемого параметра может иметь синтаксис (1):
| (начиная с C++14) |
| (начиная с C++17) |
| (начиная с C++20) |
Объявления функций
Тип-заполнитель может встречаться в спецификаторах объявления декларатора функции, содержащего завершающий тип возвращаемого значения.
| Тип-заполнитель может встречаться в спецификаторах объявления или спецификаторах типа объявленного типа возвращаемого значения декларатора функции. В этом случае применяется вывод типа возвращаемого значения. | (начиная с C++14) |
auto f() -> int; // OK: f returns int
auto g() { return 0.0; } // OK since C++14: g returns double
auto h(); // OK since C++14: h’s return type will be deduced when it is defined
Объявления переменных
Тип переменной, объявленной с использованием типа-заполнителя, выводится из её инициализатора. Такое использование допускается в объявлении переменной с инициализацией.
Тип-заполнитель может встречаться только как один из спецификаторов объявления в последовательности спецификаторов объявления или как один из спецификаторов типа в завершающем типе возвращаемого значения, который задаёт тип, заменяющий такой спецификатор объявления. В этом случае объявление должно объявлять как минимум одну переменную, и каждая переменная должна иметь непустой инициализатор.
// “auto”s in declaration specifiers
auto x = 5; // OK: x has type int
const auto *v = &x, u = 6; // OK: v has type const int*, u has type const int
static auto y = 0.0; // OK: y has type double
auto f() -> int;
auto (*fp)() -> auto = f; // OK: the “auto” in the trailing return type
// can be deduced from f
Объявления структурированных привязокСпецификатор auto можно использовать в объявлении структурированной привязки. | (начиная с C++17) |
Выражения new
Тип-заполнитель можно использовать в последовательности спецификаторов типа в type-id выражения new. В таком type-id тип-заполнитель должен встречаться как один из спецификаторов типа в последовательности спецификаторов типа или в завершающем типе возвращаемого значения, который задаёт тип, заменяющий такой спецификатор типа.
Приведение в функциональном стилеСпецификатор типа auto можно использовать в качестве спецификатора типа приведения в функциональном стиле. | (начиная с C++23) |
Примечания
До C++11 auto имел семантику спецификатора длительности хранения.
Программа, использующая тип-заполнитель в контексте, явно не указанном выше, некорректна.
Если объявление объявляет несколько сущностей и последовательность спецификаторов объявления использует тип-заполнитель, программа некорректна, если выполняется хотя бы одно из следующих условий:
- Некоторые из объявленных сущностей не являются переменными.
- Тип, заменяющий тип-заполнитель, неодинаков при каждом выводе.
auto f() -> int, i = 0; // Error: declares a function and a variable with “auto”
auto a = 5, b = {1, 2}; // Error: different types for “auto”
| Ключевое слово auto также можно использовать в спецификаторе вложенного имени. Спецификатор вложенного имени вида | (Техническая спецификация concepts) |
| Макрос проверки наличия функции | Значение | Стандарт | Функция |
|---|---|---|---|
__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) также являлся заполнителем | в этом случае не является заполнителем |
| CWG 1892 | C++11 | тип возвращаемого значения в type-id указателя на функцию мог быть auto | запрещено |
| CWG 2476 | C++11 | решение CWG issue 1892 запрещало вывод типа возвращаемого значения переменных-указателей на функции из инициализаторов | разрешено |
Ссылки
- Стандарт C++23 (ISO/IEC 14882:2024):
- 9.2.9.6 Спецификаторы-заполнители типа [dcl.spec.auto]
- Стандарт C++20 (ISO/IEC 14882:2020):
- 9.2.8.5 Спецификаторы-заполнители типа [dcl.spec.auto]
- Стандарт C++17 (ISO/IEC 14882:2017):
- 10.1.7.4 Спецификатор
auto[dcl.spec.auto] - Стандарт C++14 (ISO/IEC 14882:2014):
- 7.1.6.4 Спецификатор
auto[dcl.spec.auto] - Стандарт C++11 (ISO/IEC 14882:2011):
- 7.1.6.4 Спецификатор
auto[dcl.spec.auto]
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/language/auto