Est
auto x = initializer;
équivalent à
decltype(initializer) x = initializer;
ou
decltype((initializer)) x = initializer;
ou non?
Est
auto x = initializer;
équivalent à
decltype(initializer) x = initializer;
ou
decltype((initializer)) x = initializer;
ou non?
decltype
estime également que l'expression est rvalue
ou lvalue
.
Le type indiqué par decltype peut être différent du type de déduire de l'auto.
#include <vector>
int main()
{
const std::vector<int> v(1);
auto a = v[0]; // a has type int
decltype(v[0]) b = 1; // b has type const int&, the return type of
// std::vector<int>::operator[](size_type) const
auto c = 0; // c has type int
auto d = c; // d has type int
decltype(c) e; // e has type int, the type of the entity named by c
decltype((c)) f = c; // f has type int&, because (c) is an lvalue
decltype(0) g; // g has type int, because 0 is an rvalue
}
C'est à peu près explique la différence importante. Avis decltype(c)
et decltype((c))
ne sont pas les mêmes!
Et parfois, auto
et decltype
travaille ensemble dans un esprit de coopération, comme dans l'exemple suivant (tiré de wiki, et un peu modifié):
int& foo(int& i);
float foo(float& f);
template <class T>
auto f(T& t) −> decltype(foo(t))
{
return foo(t);
}
Wikipedia plus explique la sémantique de l' decltype
comme suit:
De même pour l'opérateur sizeof, l'opérande de decltype est non évaluée. De manière informelle, le type retourné par decltype(e) est déduite comme suit:
- Si l'expression e fait référence à une variable locale ou de l'espace de la portée, à un membre statique variable ou un paramètre de fonction, alors le résultat est que la variable ou d'un paramètre de type déclaré de
- Si e est un appel de fonction ou un opérateur surchargé invocation, decltype(e) désigne la déclaration de type de retour de cette fonction
- Sinon, si e est une lvalue, decltype(e) est en T&, où T est le type de e; si e est une rvalue, le résultat est T
Ces sémantiques ont été conçus pour répondre aux besoins de la bibliothèque générique des écrivains, alors que dans le même temps, d'être intuitif pour les programmeurs débutants, parce que le type de retour de decltype correspond toujours au type de l'objet ou de la fonction exactement comme il l'a déclaré dans le code source. Plus formellement, la Règle 1 s'applique sans parenthèse id-expressions et membre de la classe des expressions dont l'accès. Pour les appels de fonction, le déduit type est le type de retour de la statique fonction choisie, tel que déterminé par les règles pour la résolution de surcharge. Exemple:
const int&& foo();
int i;
struct A { double x; };
const A* a = new A();
decltype(foo()) x1; // type is const int&&
decltype(i) x2; // type is int
decltype(a->x) x3; // type is double
decltype((a->x)) x4; // type is const double&
La raison de la différence entre ces deux invocations de decltype est que la mise entre parenthèses de l'expression (a->x) est ni un id d'expression, ni membre de l'accès à l'expression, et, par conséquent, ne désigne pas un objet nommé.Parce que l'expression est une lvalue, ses déduit de type "référence pour le type de l'expression", ou const double&.
Il dépend. auto
et decltype
servent à des fins différentes, donc ils n'ont pas de carte un-à-un.
Les règles d' auto
sont les plus faciles à expliquer, car ils sont les mêmes que pour le paramètre de modèle de déduction. Je ne vais pas développer ici, mais notez que l' auto&
et auto&&
sont également quelques utilisations possibles!
decltype
a cependant plusieurs cas, dont certains que vous avez illustré ci-dessus (l'information et de citations tirées de n3290, 7.1.6.2 Simple spécificateurs de type [dcl.type.simple]) que j'ai séparé en deux catégories:
Officieusement, je dirais que c' decltype
peut opérer sur les deux noms (pour le premier cas) ou des expressions. (Officiellement, et selon la grammaire decltype
fonctionne sur des expressions, pensez donc à le premier cas comme un raffinement et le deuxième cas, comme un fourre-tout.)
Lors de l'utilisation d'un nom avec decltype, vous obtenez l' a déclaré le type de l'entité. Ainsi, par exemple, decltype(an_object.a_member)
est le type de membre tel qu'il apparaît dans la définition de la classe. D'autre part, si nous utilisons decltype( (an_object.a_member) )
nous nous trouvons dans le fourre-tout cas et nous sommes en inspectant le type de l'expression , telle qu'elle apparaît dans le code.
En conséquence, la façon de couvrir tous les cas de vos questions:
int initializer;
auto x = initializer; // type int
// equivalent since initializer was declared as int
decltype(initializer) y = initializer;
enum E { initializer };
auto x = initializer; // type E
// equivalent because the expression is a prvalue of type E
decltype( (initializer) ) y = initializer;
struct {
int const& ializer;
} init { 0 };
auto x = init.ializer; // type int
// not equivalent because declared type is int const&
// decltype(init.ializer) y = init.ializer;
// not equivalent because the expression is an lvalue of type int const&
// decltype( (init.ializer) ) y = init.ializer;
initializer
est un tableau, alors decltype(x)
ou decltype((x))
ne fonctionnent pas simplement dessus. Cependant, auto
seront déduits d'un pointeur. initializer
est une fonction, alors l'application de decltype(fp)
sera déduite du type de fonction, auto
sera déduite de son type de retour. Donc, en général, auto
ne peut pas être considéré comme un remplacement de la version decltype()
vous avez demandée.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.