Спецификаторы типа заполнителя (начиная с C++11)
Для переменных указывает, что тип объявляемой переменной будет автоматически выведен из её инициализатора.
Для функций указывает, что тип возвращаемого значения будет выведен из их операторов return. | (начиная с C++14) |
Для параметров шаблона, не относящихся к типу, указывает, что тип будет выведен из аргумента. | (начиная с C++17) |
Содержание |
[править]Синтаксис
ограничение-типа (необязательно)auto | (1) | (начиная с C++11) | |||||||
ограничение-типа (необязательно)decltype(auto) | (2) | (начиная с C++14) | |||||||
ограничение-типа | — | (начиная с C++20) имя концепта, необязательно уточнённое, за которым может следовать список аргументов шаблона, заключённый в <> |
decltype(выражение)
, где выражение
это инициализатор или то, что используется в операторах возврата.Заполнитель auto может сопровождаться модификаторами, такими как const или &, которые будут участвовать в выводе типа. Заполнитель decltype(auto) должен быть единственным компонентом объявленного типа.(начиная с C++14)
[править]Объяснение
Спецификатор типа заполнителя может появляться в следующих контекстах:
- в последовательности спецификатора типа переменной: auto x = выражение; в качестве спецификатора типа. Тип выводится из инициализатора.
Если спецификатором типа заполнителя являетсяauto
или ограничение-типаauto
(начиная с C++20), тип переменной выводится из инициализатора с использованием правил для вывода аргумента шаблона из вызова функции (для подробностей смотрите вывод аргумента шаблона — другие контексты).
Например, при данном constauto& i = выражение;, типi
в точности совпадёт с типом аргументаu
в воображаемом шаблоне template<class U>void f(const U& u), если вызов функции f(выражение) был скомпилирован. Следовательно, auto&& может быть выведено либо как ссылка lvalue, либо как ссылка rvalue в соответствии с инициализатором, который используется в цикле for на основе диапазона.Если спецификатор типа заполнителя имеет вид
decltype(auto)
или ограничение-типаdecltype(auto)
(начиная с C++20), выведенный тип этоdecltype(выражение)
, гдевыражение
это инициализатор.(начиная с C++14) Если спецификатор типа заполнителя используется для объявления нескольких переменных, выведенные типы должны совпадать. Например, объявление auto i =0, d =0.0; некорректно, а объявление auto i =0, *p =&i; правильно и
auto
выводится как int. - в идентификаторе типа выражения new. Тип выводится из инициализатора. Для
new Tинициализатор
(гдеT
содержит тип-заполнитель, инициализатор является либо инициализатором в скобках, либо списком инициализаторов в фигурных скобках), типT
выводится, как для переменнойx
в придуманном объявлении T x инициализатор;. - (начиная с C++14) в возвращаемом типе функции или лямбда-выражения: auto& f();. Тип возвращаемого значения выводится из операнда не отброшенного(начиная с C++17)оператора return.
Смотрите функция — вывод типа возвращаемого значения. - (начиная с C++17) в объявлении параметра шаблона не типа: template<auto I>struct A;. Его тип выводится из соответствующего аргумента.
Спецификатор auto может также появляться в спецификаторе простого типа явного преобразование типа: auto(выражение) и auto{выражение}. Его тип выводится из выражения. | (начиная с C++23) |
Кроме того,
| (начиная с C++14) |
Ограничение типаЕсли присутствует ограничение-типа, пусть
Вывод невозможен, если выражение ограничения недопустимо или возвращает | (начиная с C++20) |
[править]Примечание
До C++11, auto имел семантику спецификатора длительности хранения.
Смешивание auto
переменных и функций в одном объявлении, как в auto f()->int, i =0; не допускается.
Спецификатор auto также может использоваться с декларатором функции, за которым следует конечный возвращаемый тип, и в этом случае объявленный возвращаемый тип является завершающим возвращаемым типом (который также может быть типом-заполнителем).
auto(*p)()->int;// объявляет p как указатель на функцию, возвращающую intauto(*q)()->auto= p;// объявляет q как указатель на функцию, возвращающую T,// где T выводится из типа p
Спецификатор auto также может использоваться в объявлении структурной привязки. | (начиная с C++17) |
Ключевое слово auto также может использоваться в спецификаторе-вложенного-имени. Спецификатор-вложенного-имени в форме auto:: это заполнитель, который заменяется классом или типом перечисления в соответствии с правилами вывода заполнителя ограниченного типа. | (ТС концепций) |
Макрос Тестирования функциональности | Значение | Стандарт | Функциональность |
---|---|---|---|
__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++17auto f()->std::pair<decltype(n), decltype(n)>// auto не может вывести из списка// инициализации в скобках{return{n, n};} int main(){auto a =1+2;// тип a равен intauto 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&, псевдоним astd::cout<<"до модификации через c2, a = "<< a <<'\n';++c2;std::cout<<" после модификации через 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);// подавляет предупреждения о// "неиспользуемой переменной"}
Возможный вывод:
до модификации через c2, a = 3 после модификации через c2, a = 4
[править]Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
Номер | Применён | Поведение в стандарте | Корректное поведение |
---|---|---|---|
CWG 1265 | C++11 | спецификатор auto можно использовать для объявления функции с конечным возвращаемым типом и определения переменной в одном операторе объявления | запрещено |
CWG 1346 | C++11 | список выражений в скобках не может быть присвоен автоматической переменной | разрешено |
CWG 1347 | C++11 | объявление со спецификатором auto может определять две переменные с типами T и std::initializer_list<T> соответственно | запрещено |
CWG 1852 | C++14 | спецификатор auto в decltype(auto) также был заполнителем | не заполнитель в данном случае |