Placeholder type specifiers (since C++11)
Спецификатор типа-заполнителя обозначает тип-заполнитель , который будет заменён позднее, обычно путём вывода из инициализатора .
Содержание |
Синтаксис
type-constraint
(optional)
auto
|
(1) | ||||||||
type-constraint
(optional)
decltype(auto)
|
(2) | (since C++14) | |||||||
| type-constraint | - |
(since C++20)
имя
концепта
, опционально квалифицированное, опционально сопровождаемое списком шаблонных аргументов в
<>
|
decltype(expr)
, где
expr
представляет собой инициализатор или операнды, используемые в
операторах return
.
Заполнитель
auto
может сопровождаться модификаторами, такими как
const
или
&
, которые будут участвовать в выводе типа.
Заполнитель
decltype
(
auto
)
должен быть единственным компонентом объявленного типа.
(начиная с C++14)
|
Если присутствует
type-constraint
, пусть
Вывод завершается неудачей, если constraint expression является недопустимым или возвращает false . |
(since C++20) |
Объяснение
Заполнитель спецификатора типа может появляться в следующих контекстах:
Объявления параметровВ следующих объявлениях параметров тип объявленного параметра может быть синтаксиса (1) :
|
(since C++14) |
|
(since C++17) |
|
(since C++20) |
Объявления функций
Заполнитель типа может появляться в спецификаторах объявления для декларатора функции , который включает конечный тип возврата.
|
Замещающий тип может появляться в спецификаторах объявления или спецификаторах типа в объявленном возвращаемом типе декларатора функции . Вывод возвращаемого типа будет применён в этом случае. |
(начиная с C++14) |
auto f() -> int; // OK: f возвращает int auto g() { return 0.0; } // OK начиная с C++14: g возвращает double auto h(); // OK начиная с C++14: возвращаемый тип h будет выведен при его определении
Объявления переменных
Тип переменной, объявленной с использованием типа-заполнителя, выводится из её инициализатора . Такое использование разрешено в инициализирующем объявлении переменной.
Замещающий тип может появляться только как один из спецификаторов объявления в последовательности спецификаторов объявления или как один из спецификаторов типа в завершающем возвращаемом типе, который указывает тип, заменяющий такой спецификатор объявления. В этом случае объявление должно объявлять как минимум одну переменную, и каждая переменная должна иметь непустой инициализатор.
// "auto" в спецификаторах объявления auto x = 5; // OK: x имеет тип int const auto *v = &x, u = 6; // OK: v имеет тип const int*, u имеет тип const int static auto y = 0.0; // OK: y имеет тип double auto f() -> int; auto (*fp)() -> auto = f; // OK: "auto" в конце возвращаемого типа // может быть выведен из f
Объявления структурированных привязокСпецификатор auto может использоваться в объявлении структурированной привязки . |
(начиная с C++17) |
new выражения
Заполнитель типа может использоваться в последовательности спецификаторов типа type-id для new expression . В таком type-id заполнитель типа должен появляться как один из спецификаторов типа в последовательности спецификаторов типа или как завершающий возвращаемый тип, который определяет тип, заменяющий такой спецификатор типа.
Функциональное приведение типаСпецификатор типа auto может использоваться как спецификатор типа для функционального приведения типа . |
(начиная с C++23) |
Примечания
До C++11, auto имел семантику спецификатора продолжительности хранения .
Программа, использующая тип-заполнитель в контексте, не указанном явно выше, является некорректной.
Если объявление объявляет несколько сущностей, и последовательность спецификаторов объявления использует тип-заполнитель, программа является некорректной, если выполняется любое из следующих условий:
- Некоторые из объявленных сущностей не являются переменными.
- Тип, заменяющий тип-заполнитель, не совпадает в каждом выводе.
auto f() -> int, i = 0; // Ошибка: объявляет функцию и переменную с "auto" auto a = 5, b = {1, 2}; // Ошибка: разные типы для "auto"
Если функция или переменная с незамещенным типом-заполнителем используется в выражении, программа является некорректной.
auto v = 1; auto l = [&] { v++; return l;// Ошибка: тип-заполнитель для l не был заменён }; std::function<void()> p = [&] { v++; return p;// OK };
|
Ключевое слово auto также может использоваться в квалификаторе вложенного имени. Квалификатор вложенного имени вида auto :: является заполнителем, который заменяется на тип класса или перечисления в соответствии с правилами вывода типа для ограниченного заполнителя . |
(concepts TS) |
| Макрос проверки возможности | Значение | Стандарт | Возможность |
|---|---|---|---|
__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; } // возвращаемый тип - это тип operator+(T, U) // идеальная переадресация вызова функции должна использовать decltype(auto) // на случай, если вызываемая функция возвращает по ссылке template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // C++17 объявление параметра auto auto f() -> std::pair<decltype(n), decltype(n)> // auto не может вывести из списка инициализации { return {n, n}; } int main() { auto a = 1 + 2; // тип a - int auto b = add(1, 1.2); // тип b - double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // тип c0 - int, содержит копию a decltype(auto) c1 = a; // тип c1 - int, содержит копию a decltype(auto) c2 = (a); // тип c2 - int&, псевдоним 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>(); // декларация структурированной привязки auto d = {1, 2}; // OK: тип d - std::initializer_list<int> auto n = {5}; // OK: тип n - std::initializer_list<int> // auto e{1, 2}; // Ошибка согласно DR n3922, ранее std::initializer_list<int> auto m{5}; // OK: тип m - int согласно DR n3922, ранее initializer_list<int> // decltype(auto) z = { 1, 2 } // Ошибка: {1, 2} не является выражением // auto часто используется для безымянных типов, таких как типы лямбда-выражений auto lambda = [](int x) { return x + 3; }; // auto int x; // допустимо в C++98, ошибка в C++11 // auto x; // допустимо в C, ошибка в C++ [](...){}(c0, c1, v, w, d, n, m, lambda); // подавляет предупреждения "неиспользуемая переменная" }
Возможный вывод:
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
запрещало выведение
возвращаемого типа переменных указателей на функцию из инициализаторов |
разрешено |
| N3922 | C++11 | прямая инициализация списком для auto выводит std::initializer_list |
некорректно для более чем одного
элемента, выводит тип элемента для одного элемента |
Ссылки
- Стандарт 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]
-
10.1.7.4 Спецификатор
- Стандарт C++14 (ISO/IEC 14882:2014):
-
-
7.1.6.4
autoспецификатор [dcl.spec.auto]
-
7.1.6.4
- Стандарт C++11 (ISO/IEC 14882:2011):
-
-
7.1.6.4
autoспецификатор [dcl.spec.auto]
-
7.1.6.4