Placeholder type specifiers (since C++11)
Un especificador de tipo de marcador de posición designa un tipo de marcador de posición que será reemplazado posteriormente, típicamente por deducción de un inicializador .
Contenidos |
Sintaxis
type-constraint
(opcional)
auto
|
(1) | ||||||||
type-constraint
(opcional)
decltype(auto)
|
(2) | (desde C++14) | |||||||
| type-constraint | - |
(since C++20)
un
concept
nombre, opcionalmente calificado, opcionalmente seguido por una lista de argumentos de plantilla encerrada en
<>
|
decltype(expr)
, donde
expr
es el inicializador o los operandos utilizados en
sentencias return
.
El marcador de posición
auto
puede ir acompañado de modificadores, como
const
o
&
, que participarán en la deducción de tipo.
El marcador de posición
decltype
(
auto
)
debe ser el único constituyente del tipo declarado.
(desde C++14)
|
Si está presente
type-constraint
, sea
La deducción falla si la expresión de restricción es inválida o devuelve false . |
(desde C++20) |
Explicación
Un especificador de tipo de marcador de posición puede aparecer en los siguientes contextos:
Declaraciones de parámetrosEn las siguientes declaraciones de parámetros, el tipo del parámetro declarado puede ser de sintaxis (1) :
|
(since C++14) |
|
(since C++17) |
|
(since C++20) |
Declaraciones de funciones
Un tipo de marcador de posición puede aparecer en los especificadores de declaración para un declarador de función que incluye un tipo de retorno final.
|
Un tipo de marcador de posición puede aparecer en los especificadores de declaración o especificadores de tipo en el tipo de retorno declarado de un declarador de función . La deducción del tipo de retorno se aplicará en este caso. |
(since C++14) |
auto f() -> int; // OK: f devuelve int auto g() { return 0.0; } // OK desde C++14: g devuelve double auto h(); // OK desde C++14: el tipo de retorno de h se deducirá cuando se defina
Declaraciones de variables
El tipo de una variable declarada utilizando un tipo de marcador de posición se deduce de su inicializador . Este uso está permitido en una declaración de inicialización de una variable.
El tipo de marcador de posición solo puede aparecer como uno de los especificadores de declaración en la secuencia de especificadores de declaración o como uno de los especificadores de tipo en un tipo de retorno final que especifica el tipo que reemplaza dicho especificador de declaración. En este caso, la declaración debe declarar al menos una variable, y cada variable debe tener un inicializador no vacío.
// “auto”s en especificadores de declaración auto x = 5; // OK: x tiene tipo int const auto *v = &x, u = 6; // OK: v tiene tipo const int*, u tiene tipo const int static auto y = 0.0; // OK: y tiene tipo double auto f() -> int; auto (*fp)() -> auto = f; // OK: el “auto” en el tipo de retorno final // puede deducirse de f
Declaraciones de enlace estructuradoEl especificador auto puede utilizarse en una declaración de enlace estructurado . |
(desde C++17) |
new expressions
Un tipo de marcador de posición puede utilizarse en la secuencia de especificadores de tipo del type-id de una expresión new . En dicho type-id, el tipo de marcador de posición debe aparecer como uno de los especificadores de tipo en la secuencia de especificadores de tipo o un tipo de retorno final que especifique el tipo que reemplaza dicho especificador de tipo.
Conversión de estilo funciónEl especificador de tipo auto puede utilizarse como especificador de tipo de una conversión de estilo función . |
(since C++23) |
Notas
Hasta C++11, auto tenía la semántica de un especificador de duración de almacenamiento .
Un programa que utiliza un tipo de marcador de posición en un contexto no explícitamente establecido anteriormente está mal formado.
Si una declaración declara múltiples entidades, y la secuencia de especificadores de declaración utiliza un tipo de marcador de posición, el programa está mal formado si se satisface alguna de las siguientes condiciones:
- Algunas de las entidades declaradas no son variables.
- El tipo que reemplaza al tipo de marcador de posición no es el mismo en cada deducción.
auto f() -> int, i = 0; // Error: declara una función y una variable con "auto" auto a = 5, b = {1, 2}; // Error: tipos diferentes para "auto"
Si una función o variable con un tipo de marcador de posición no reemplazado es referenciada por una expresión, el programa está mal formado.
auto v = 1; auto l = [&] { v++; return l;// Error: El tipo de marcador de posición para l no fue reemplazado }; std::function<void()> p = [&] { v++; return p;// Correcto };
|
La palabra clave auto también puede utilizarse en un especificador de nombre anidado. Un especificador de nombre anidado de la forma auto :: es un marcador de posición que se reemplaza por un tipo de clase o enumeración siguiendo las reglas para la deducción de marcador de posición de tipo restringido . |
(concepts TS) |
| Macro de prueba de características | Valor | Std | Característica |
|---|---|---|---|
__cpp_decltype_auto
|
201304L
|
(C++14) | decltype ( auto ) |
Palabras clave
Ejemplo
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // el tipo de retorno es el tipo de operator+(T, U) // el reenvío perfecto de una llamada a función debe usar decltype(auto) // en caso de que la función llamada retorne por referencia template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // declaración de parámetro auto de C++17 auto f() -> std::pair<decltype(n), decltype(n)> // auto no puede deducir de lista de inicialización entre llaves { return {n, n}; } int main() { auto a = 1 + 2; // tipo de a es int auto b = add(1, 1.2); // tipo de b es double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // tipo de c0 es int, contiene una copia de a decltype(auto) c1 = a; // tipo de c1 es int, contiene una copia de a decltype(auto) c2 = (a); // tipo de c2 es int&, un alias de 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>(); //declaración de enlace estructurado auto d = {1, 2}; // OK: tipo de d es std::initializer_list<int> auto n = {5}; // OK: tipo de n es std::initializer_list<int> // auto e{1, 2}; // Error según DR n3922, std::initializer_list<int> antes auto m{5}; // OK: tipo de m es int según DR n3922, initializer_list<int> antes // decltype(auto) z = { 1, 2 } // Error: {1, 2} no es una expresión // auto se usa comúnmente para tipos sin nombre como los tipos de expresiones lambda auto lambda = [](int x) { return x + 3; }; // auto int x; // válido en C++98, error a partir de C++11 // auto x; // válido en C, error en C++ [](...){}(c0, c1, v, w, d, n, m, lambda); // suprime advertencias de "variable no utilizada" }
Salida posible:
before modification through c2, a = 3 after modification through c2, a = 4
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 1265 | C++11 |
el especificador
auto
podía usarse para declarar una función con un tipo de retorno
final y definir una variable en una misma sentencia de declaración |
prohibido |
| CWG 1346 | C++11 |
una lista de expresiones entre paréntesis no podía asignarse a una
variable auto |
permitido |
| CWG 1347 | C++11 |
una declaración con el especificador
auto
podía definir dos variables
con tipos
T
y
std::
initializer_list
<
T
>
respectivamente
|
prohibido |
| CWG 1852 | C++14 | el especificador auto en decltype ( auto ) también era un marcador de posición |
no es un marcador de posición
en este caso |
| CWG 1892 | C++11 | el tipo de retorno de un type-id de puntero a función podía ser auto | prohibido |
| CWG 2476 | C++11 |
la resolución de
CWG issue 1892
prohibía la deducción
del tipo de retorno de variables puntero a función desde inicializadores |
permitido |
| N3922 | C++11 | la inicialización directa por lista de auto deduce std::initializer_list |
mal formado para más de un
elemento, deduce el tipo del elemento para un solo elemento |
Referencias
- Estándar C++23 (ISO/IEC 14882:2024):
-
- 9.2.9.6 Especificadores de tipo de marcador de posición [dcl.spec.auto]
- Estándar C++20 (ISO/IEC 14882:2020):
-
- 9.2.8.5 Especificadores de tipo de marcador de posición [dcl.spec.auto]
- Estándar C++17 (ISO/IEC 14882:2017):
-
-
10.1.7.4 El especificador
auto[dcl.spec.auto]
-
10.1.7.4 El especificador
- Estándar C++14 (ISO/IEC 14882:2014):
-
-
7.1.6.4
autoespecificador [dcl.spec.auto]
-
7.1.6.4
- Estándar C++11 (ISO/IEC 14882:2011):
-
-
7.1.6.4
autoespecificador [dcl.spec.auto]
-
7.1.6.4