Символыauto и используются для обозначения типа заполнителя, который позже будет заменен путем вычитания из инициализатора. Также используется , чтобы ввести тип функции , имеющий или чтобы показать , что лямбда является общим лямбда ( ). Также используется для введения .decltype(auto) type-specifiersauto type-specifiertrailing-return-type[expr.prim.lambda.closure]auto type-specifierstructured binding declaration
Тип заполнитель может появиться с функцией описателем в decl-specifier-seq, type-specifier-seq, conversion-function-id, или trailing-return-type, в любом контексте , где такой описатель является действительным. Если декларатор функции включает в себя trailing-return-type([dcl.fct]), который trailing-return-typeуказывает объявленный тип возвращаемого значения функции. В противном случае декларатор функции должен объявить функцию. Если объявленный тип возвращаемого значения функции содержит тип-заполнитель, тип возвращаемого значения функции выводится из неотброшенныхreturn операторов, если таковые имеются, в теле функции ([stmt.if]).
Если появляется как один из в a из a , лямбда - это ( ). [auto type-specifierdecl-specifiers decl-specifier-seqparameter-declarationlambda-expressiongeneric lambda [expr.prim.lambda.closure] Example:
auto glambda = [](int i, auto a) { return i; }; // OK: a generic lambda
— end example ]
Тип переменной, объявленной с использованиемauto илиdecltype(auto) , выводится из ее инициализатора. Это использование разрешено в инициализирующем объявлении ([dcl.init]) переменной. auto илиdecltype(auto) должно отображаться как одно из decl-specifiers в, decl-specifier-seqа за ним decl-specifier-seq должно следовать одно или несколько declarators, за каждым из которых должно следовать непустое значение initializer. В initializerформе
( expression-list )
это expression-listдолжно быть единым assignment-expression. [ Example:
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 int r; // error: auto is not a storage-class-specifier auto f() -> int; // OK: f returns int auto g() { return 0.0; } // OK: g returns double auto h(); // OK: h's return type will be deduced when it is defined
— end example ]
Тип заполнитель также может быть использован в type-specifier-seqв new-type-idили type-idв А new-expression и , как decl-specifier из parameter-declaration-е decl-specifier-seq в template-parameter.
Программа, которая используетauto илиdecltype(auto) в контексте, явно не разрешенном в этом разделе, имеет неправильный формат.
Если init-declarator-listсодержит более одного init-declarator, все они должны формировать объявления переменных. Тип каждой объявленной переменной определяетсяplaceholder type deduction, и если тип, заменяющий тип заполнителя, не является одинаковым при каждом выводе, программа имеет неправильный формат.
[ Example:
auto x = 5, *y = &x; // OK: auto is int auto a = 5, b = { 1, 2 }; // error: different types for auto
— end example ]
Если функция с объявленным типом возвращаемого значения, содержащим тип заполнителя, имеет несколько неотброшенныхreturn операторов, тип возвращаемого значения выводится для каждого такогоreturn оператора. Если выведенный тип не является одинаковым в каждом из выводов, программа сформирована неправильно.
Если функция с объявленным типом возврата, которая использует тип заполнителя, не имеет неотброшенныхreturn операторов, тип возвращаемого значения выводится, как если бы из return оператора без операнда в закрывающей фигурной скобке тела функции. [ Example:
auto f() { } // OK, return type is void auto* g() { } // error, cannot deduce auto* from void()
— end example ]
Если для определения типа выражения требуется тип сущности с невыявленным типом заполнителя, программа имеет неправильный формат. Однако после того, как неотброшенныйreturn оператор был замечен в функции, тип возвращаемого значения, выведенный из этого оператора, можно использовать в остальной части функции, в том числе в других return операторах. [ Example:
auto n = n; // error, n's type is unknown auto f(); void g() { &f; } // error, f's return type is unknown auto sum(int i) { if (i == 1) return i; // sum's return type is int else return sum(i-1)+i; // OK, sum's return type has been deduced }
— end example ]
Вывод типа возвращаемого значения для шаблона функции с заполнителем в объявленном типе происходит при создании экземпляра определения, даже если тело функции содержитreturn оператор с операндом, не зависящим от типа. [ Note: Следовательно, любое использование специализации шаблона функции вызовет неявное создание экземпляра. Любые ошибки, возникающие из-за этого экземпляра, не относятся к непосредственному контексту типа функции и могут привести к неправильному формату программы ([temp.deduct]). ] [ — end note Example:
template <class T> auto f(T t) { return t; } // return type deduced at instantiation time typedef decltype(f(1)) fint_t; // instantiates f<int> to deduce return type template<class T> auto f(T* t) { return *t; } void g() { int (*p)(int*) = &f; } // instantiates both fs to determine return types, // chooses second
— end example ]
Повторные объявления или специализации функции или шаблона функции с объявленным типом возврата, который использует тип заполнителя, также должны использовать этот заполнитель, а не выводимый тип. [ Example:
auto f(); auto f() { return 42; } // return type is int auto f(); // OK int f(); // error, cannot be overloaded with auto f() decltype(auto) f(); // error, auto and decltype(auto) don't match template <typename T> auto g(T t) { return t; } // #1 template auto g(int); // OK, return type is int template char g(char); // error, no matching template template<> auto g(double); // OK, forward declaration with unknown return type template <class T> T g(T t) { return t; } // OK, not functionally equivalent to #1 template char g(char); // OK, now there is a matching template template auto g(float); // still matches #1 void h() { return g(42); } // error, ambiguous template <typename T> struct A { friend T frf(T); }; auto frf(int i) { return i; } // not a friend of A<int>
— end example ]
Anexplicit instantiation declaration не вызывает создание экземпляра сущности, объявленной с использованием типа заполнителя, но также не предотвращает создание экземпляра этой сущности по мере необходимости для определения ее типа. [ Example:
template <typename T> auto f(T t) { return t; } extern template auto f(int); // does not instantiate f<int> int (*p)(int) = f; // instantiates f<int> to determine its return type, but an explicit // instantiation definition is still required somewhere in the program
— end example ]
Placeholder type deduction - это процесс, с помощью которого тип, содержащий тип-заполнитель, заменяется выведенным типом.
Тип,T содержащий тип заполнителя и соответствующий инициализаторe, определяются следующим образом:
для неотброшенногоreturn оператора, который встречается в функции, объявленной с возвращаемым типом, который содержит тип-заполнитель, T является объявленным возвращаемым типом иe является операндомreturn оператора. Если уreturn оператора нет операнда, тоe естьvoid();
для переменной, объявленной с типом, содержащим тип-заполнитель, T является объявленным типом переменной иe инициализатором. Если инициализация - это инициализация с прямым списком, инициализатор должен braced-init-list содержать только один элемент assignment-expression иe является assignment-expression;
для параметра шаблона, не являющегося типом, объявленного с типом, содержащим тип-заполнитель, T является объявленным типом параметра шаблона, не являющимся типом, иe является соответствующим аргументом шаблона.
В случаеreturn заявления, без операнда или с операндом типаvoid, T должны быть либо decltype(auto) илиcvauto.
Если вывод предназначен дляreturn оператора иe представляет собой braced-init-list([dcl.init.list]), программа сформирована неправильно.
Если заполнитель - это , замена выведенного типа определяется с использованием правил вывода аргументов шаблона. Получить от путем замены вхождений либо на новый параметр шаблона изобретенного типа, либо, если инициализация - инициализация списка-копирования, на . Выведите значение для использования правил , где - тип параметра шаблона функции, а соответствующий аргумент - . Если вычет не удается, декларация имеет неверный формат. В противном случае получается заменой выведенного на . [auto type-specifierT' TP T auto U std::initializer_list<U>U template argument deduction from a function callP eT' U P Example:
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> auto x2 = { 1, 2.0 }; // error: cannot deduce element type auto x3{ 1, 2 }; // error: not a single element auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int> auto x5{ 3 }; // decltype(x5) is int
— end example ]
[ Example:
const auto &i = expr;
Типi - это выведенный тип параметраu при вызовеf(expr) следующего шаблона придуманной функции:
template <class U> void f(const U& u);
— end example ]
Если заполнителем является , должен быть только заполнитель. Тип, выведенный для , определяется, как описано в , как если бы он был операндом . [decltype(auto) type-specifierT T [dcl.type.simple]e decltype Example:
int i; int&& f(); auto x2a(i); // decltype(x2a) is int decltype(auto) x2d(i); // decltype(x2d) is int auto x3a = i; // decltype(x3a) is int decltype(auto) x3d = i; // decltype(x3d) is int auto x4a = (i); // decltype(x4a) is int decltype(auto) x4d = (i); // decltype(x4d) is int& auto x5a = f(); // decltype(x5a) is int decltype(auto) x5d = f(); // decltype(x5d) is int&& auto x6a = { 1, 2 }; // decltype(x6a) is std::initializer_list<int> decltype(auto) x6d = { 1, 2 }; // error, { 1, 2 } is not an expression auto *x7a = &i; // decltype(x7a) is int* decltype(auto)*x7d = &i; // error, declared type is not plain decltype(auto)
— end example ]