Placeholder type specifiers (since C++11)
Un spécificateur de type d'espace réservé désigne un type d'espace réservé qui sera remplacé ultérieurement, généralement par déduction d'un initialiseur .
Table des matières |
Syntaxe
type-constraint
(optionnel)
auto
|
(1) | ||||||||
type-constraint
(optionnel)
decltype(auto)
|
(2) | (depuis C++14) | |||||||
| type-constraint | - |
(depuis C++20)
un nom de
concept
, éventuellement qualifié, suivi optionnellement d'une liste d'arguments template entre
<>
|
decltype(expr)
, où
expr
est l'initialiseur ou les opérandes utilisés dans les
instructions return
.
Le placeholder
auto
peut être accompagné de modificateurs, tels que
const
ou
&
, qui participeront à la déduction de type.
Le placeholder
decltype
(
auto
)
doit être le seul constituant du type déclaré.
(depuis C++14)
|
Si
type-constraint
est présent, soit
La déduction échoue si l'expression de contrainte est invalide ou retourne false . |
(depuis C++20) |
Explication
Un spécificateur de type d'espace réservé peut apparaître dans les contextes suivants :
Déclarations de paramètresDans les déclarations de paramètres suivantes, le type du paramètre déclaré peut être de syntaxe (1) :
|
(depuis C++14) |
|
(depuis C++17) |
|
(depuis C++20) |
Déclarations de fonctions
Un type d'espace réservé peut apparaître dans les spécificateurs de déclaration pour un déclarateur de fonction qui inclut un type de retour en suffixe.
|
Un type d'espace réservé peut apparaître dans les spécificateurs de déclaration ou les spécificateurs de type dans le type de retour déclaré d'un déclarateur de fonction . La déduction du type de retour sera appliquée dans ce cas. |
(depuis C++14) |
auto f() -> int; // OK : f retourne int auto g() { return 0.0; } // OK depuis C++14 : g retourne double auto h(); // OK depuis C++14 : le type de retour de h sera déduit lors de sa définition
Déclarations de variables
Le type d'une variable déclarée en utilisant un type de substitution est déduit de son initialiseur . Cette utilisation est autorisée dans une déclaration d'initialisation d'une variable.
Le type de substitution ne peut apparaître que comme l'un des spécificateurs de déclaration dans la séquence de spécificateurs de déclaration ou comme l'un des spécificateurs de type dans un type de retour final qui spécifie le type remplaçant un tel spécificateur de déclaration. Dans ce cas, la déclaration doit déclarer au moins une variable, et chaque variable doit avoir un initialiseur non vide.
// Les "auto" dans les spécificateurs de déclaration auto x = 5; // OK : x a le type int const auto *v = &x, u = 6; // OK : v a le type const int*, u a le type const int static auto y = 0.0; // OK : y a le type double auto f() -> int; auto (*fp)() -> auto = f; // OK : le "auto" dans le type de retour postfixé // peut être déduit de f
Déclarations de liaisons structuréesLe spécificateur auto peut être utilisé dans une déclaration de liaison structurée . |
(depuis C++17) |
new expressions
Un type d'espace réservé peut être utilisé dans la séquence de spécificateurs de type du type-id d'une expression new . Dans un tel type-id, le type d'espace réservé doit apparaître comme l'un des spécificateurs de type dans la séquence de spécificateurs de type ou un type de retour trailing qui spécifie le type remplaçant un tel spécificateur de type.
Cast de style fonctionLe spécificateur de type auto peut être utilisé comme spécificateur de type d'un cast de style fonction . |
(depuis C++23) |
Notes
Jusqu'à C++11, auto avait la sémantique d'un spécificateur de durée de stockage .
Un programme qui utilise un type d'espace réservé dans un contexte non explicitement indiqué ci-dessus est non conforme.
Si une déclaration déclare plusieurs entités, et que la séquence de spécificateurs de déclaration utilise un type d'espace réservé, le programme est mal formé si l'une des conditions suivantes est satisfaite :
- Certaines des entités déclarées ne sont pas des variables.
- Le type qui remplace le type de substitution n'est pas le même dans chaque déduction.
auto f() -> int, i = 0; // Erreur : déclare une fonction et une variable avec "auto" auto a = 5, b = {1, 2}; // Erreur : types différents pour "auto"
Si une fonction ou une variable avec un type d'espace réservé non remplacé est référencée par une expression, le programme est mal formé.
auto v = 1; auto l = [&] { v++; return l;// Erreur : Le type d'espace réservé pour l n'a pas été remplacé }; std::function<void()> p = [&] { v++; return p;// Correct };
|
Le mot-clé auto peut également être utilisé dans un spécificateur de nom imbriqué. Un spécificateur de nom imbriqué de la forme auto :: est un espace réservé qui est remplacé par un type de classe ou d'énumération suivant les règles de déduction de type contraint pour les espaces réservés. |
(concepts TS) |
| Macro de test de fonctionnalité | Valeur | Std | Fonctionnalité |
|---|---|---|---|
__cpp_decltype_auto
|
201304L
|
(C++14) | decltype ( auto ) |
Mots-clés
Exemple
#include <iostream> #include <utility> template<class T, class U> auto add(T t, U u) { return t + u; } // le type de retour est le type de operator+(T, U) // la transmission parfaite d'un appel de fonction doit utiliser decltype(auto) // au cas où la fonction appelée retourne par référence template<class F, class... Args> decltype(auto) PerfectForward(F fun, Args&&... args) { return fun(std::forward<Args>(args)...); } template<auto n> // déclaration de paramètre auto C++17 auto f() -> std::pair<decltype(n), decltype(n)> // auto ne peut pas déduire d'une liste d'initialisation entre accolades { return {n, n}; } int main() { auto a = 1 + 2; // le type de a est int auto b = add(1, 1.2); // le type de b est double static_assert(std::is_same_v<decltype(a), int>); static_assert(std::is_same_v<decltype(b), double>); auto c0 = a; // le type de c0 est int, contenant une copie de a decltype(auto) c1 = a; // le type de c1 est int, contenant une copie de a decltype(auto) c2 = (a); // le type de c2 est int&, un alias de a std::cout << "avant modification via c2, a = " << a << '\n'; ++c2; std::cout << " après modification via c2, a = " << a << '\n'; auto [v, w] = f<0>(); // déclaration de liaison structurée auto d = {1, 2}; // OK : le type de d est std::initializer_list<int> auto n = {5}; // OK : le type de n est std::initializer_list<int> // auto e{1, 2}; // Erreur depuis DR n3922, std::initializer_list<int> avant auto m{5}; // OK : le type de m est int depuis DR n3922, initializer_list<int> avant // decltype(auto) z = { 1, 2 } // Erreur : {1, 2} n'est pas une expression // auto est couramment utilisé pour les types anonymes comme les types d'expressions lambda auto lambda = [](int x) { return x + 3; }; // auto int x; // valide en C++98, erreur depuis C++11 // auto x; // valide en C, erreur en C++ [](...){}(c0, c1, v, w, d, n, m, lambda); // supprime les avertissements "variable inutilisée" }
Sortie possible :
avant modification via c2, a = 3 après modification via c2, a = 4
Rapports de défauts
Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
| DR | Appliqué à | Comportement publié | Comportement corrigé |
|---|---|---|---|
| CWG 1265 | C++11 |
le spécificateur
auto
pouvait être utilisé pour déclarer une fonction avec un type de retour
trailing et définir une variable dans une même instruction de déclaration |
interdit |
| CWG 1346 | C++11 |
une liste d'expressions entre parenthèses ne pouvait pas être assignée à une
variable auto |
autorisé |
| CWG 1347 | C++11 |
une déclaration avec le spécificateur
auto
pouvait définir deux variables
avec les types
T
et
std::
initializer_list
<
T
>
respectivement
|
interdit |
| CWG 1852 | C++14 | le spécificateur auto dans decltype ( auto ) était aussi un placeholder |
pas un placeholder
dans ce cas |
| CWG 1892 | C++11 | le type de retour d'un type-id de pointeur de fonction pouvait être auto | interdit |
| CWG 2476 | C++11 |
la résolution de
CWG issue 1892
interdisait la déduction
du type de retour des variables de pointeur de fonction depuis les initialiseurs |
autorisé |
| N3922 | C++11 | la direct-list-initialization de auto déduit std::initializer_list |
ill-formed pour plus d'un
élément, déduit le type d'élément pour un seul élément |
Références
- Norme C++23 (ISO/CEI 14882:2024) :
-
- 9.2.9.6 Spécificateurs de type substitut [dcl.spec.auto]
- Norme C++20 (ISO/IEC 14882:2020) :
-
- 9.2.8.5 Spécificateurs de type substitut [dcl.spec.auto]
- Norme C++17 (ISO/CEI 14882:2017) :
-
-
10.1.7.4 Le spécificateur
auto[dcl.spec.auto]
-
10.1.7.4 Le spécificateur
- Norme C++14 (ISO/CEI 14882:2014) :
-
-
7.1.6.4
autospécificateur [dcl.spec.auto]
-
7.1.6.4
- Norme C++11 (ISO/CEI 14882:2011) :
-
-
7.1.6.4
autospécificateur [dcl.spec.auto]
-
7.1.6.4