web-dev-qa-db-fra.com

Quelle est la différence entre 'typedef' et 'using' en C ++ 11?

Je sais que dans C++ 11, nous pouvons maintenant utiliser using pour écrire un alias de type, comme typedefs:

typedef int MyInt;

Est-ce que, d'après ce que j'ai compris, équivaut à:

using MyInt = int;

Et cette nouvelle syntaxe est issue de la volonté de pouvoir exprimer "template typedef":

template< class T > using MyType = AnotherType< T, MyAllocatorType >;

Mais, avec les deux premiers exemples non modèles, existe-t-il d'autres différences subtiles dans la norme? Par exemple, typedefs aliasing de manière "faible". En d’autres termes, il ne crée pas un nouveau type mais seulement un nouveau nom (les conversions sont implicites entre ces noms).

Est-ce la même chose avec using ou génère-t-il un nouveau type? Y a-t-il des différences?

813
Klaim

Ils sont équivalents, de la norme (souligné par moi) (7.1.3.2):

Un nom de typedef peut également être introduit par une déclaration d'alias. L'identifiant suivant le mot-clé using devient un nom de typedef et le spécificateur d'attribut-specifier-seq optionnel suivant l'identificateur appartenant à ce nom de typedef. Il a la même sémantique que s'il avait été introduit par le spécificateur typedef. En particulier, il ne définit pas un nouveau type et il ne doit pas apparaître dans le type-id.

530
Jesse Good

La syntaxe sing présente un avantage lorsqu'elle est utilisée dans des modèles. Si vous avez besoin de l'abstraction de type, mais que vous devez également conserver le paramètre template, vous pourrez le spécifier ultérieurement. Vous devriez écrire quelque chose comme ça.

template <typename T> struct whatever {};

template <typename T> struct rebind
{
  typedef whatever<T> type; // to make it possible to substitue the whatever in future.
};

rebind<int>::type variable;

template <typename U> struct bar { typename rebind<U>::type _var_member; }

Mais en utilisant la syntaxe simplifie ce cas d'utilisation.

template <typename T> using my_type = whatever<T>;

my_type<int> variable;
template <typename U> struct baz { my_type<U> _var_member; }
190
4xy

Ils sont en grande partie les mêmes, sauf que:

La déclaration d'alias est compatible avec les modèles, alors que la typedef de style C ne l'est pas.

186
Zhongming Qu

Ils sont essentiellement les mêmes mais using fournit alias templates qui est très utile. Voici un bon exemple que je pourrais trouver:

namespace std {
 template<typename T> using add_const_t = typename add_const<T>::type;
}

Donc, nous pouvons utiliser std::add_const_t<T> au lieu de typename std::add_const<T>::type

24
Validus Oculus

Je sais que l’affiche originale apporte une excellente réponse, mais pour ceux qui trébuchent sur ce sujet, il existe une note importante de la proposition qui, à mon avis, ajoute quelque chose de précieux à la discussion, en particulier aux préoccupations de les commentaires sur le fait que le mot clé typedef soit marqué comme obsolète ou supprimé pour être redondant/ancien:

Il a été suggéré de (ré) utiliser le mot-clé typedef ... pour introduire des alias de modèles:

template<class T>
  typedef std::vector<T, MyAllocator<T> > Vec;

Cette notation présente l’avantage d’utiliser un mot-clé déjà connu pour introduire un alias de type. Cependant, il affiche également plusieurs inconvénients, parmi lesquels la confusion d'utiliser un mot clé connu pour introduire un alias pour un nom de type dans un contexte où l'alias ne désigne pas un type, mais un modèle; Vec est pas un alias pour un type, et ne doit pas être pris pour un nom de type. Le nom Vec est un nom pour la famille std::vector<•, MyAllocator<•> > - où la puce est un espace réservé pour un nom de type. Nous ne proposons donc pas la syntaxe "typedef". En revanche, la phrase

template<class T>
  using Vec = std::vector<T, MyAllocator<T> >;

peut être lu/interprété comme: à partir de maintenant, je vais utiliser Vec<T> comme synonyme de std::vector<T, MyAllocator<T> >. Avec cette lecture, la nouvelle syntaxe pour le crénelage semble raisonnablement logique.

Pour moi, cela implique une prise en charge continue du mot clé typedef en C++, car il peut encore améliorer le code lisible et compréhensible.

La mise à jour du mot clé using était spécifiquement destinée aux modèles et (comme indiqué dans la réponse acceptée) lorsque vous travaillez avec des modèles autres que les modèles using et typedef sont mécaniquement identiques. est totalement du ressort du programmeur pour des raisons de lisibilité et de communication d’intention.

3
RoboticForest