Dans C ++ 11, le using
mot clé utilisé pour type alias
est identique à typedef
.
7.1.3.2
Un typedef-name peut également être introduit par une déclaration d'alias. L'identifiant suivant le mot-clé using devient un typedef-name et l'attribut optionnel-specifier-seq qui suit l'identificateur appartient à ce typedef-name. 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 de nouveau type et il ne doit pas apparaître dans le type-id.
Bjarne Stroustrup fournit un exemple pratique:
typedef void (*PFD)(double); // C style typedef to make `PFD` a pointer to a function returning void and accepting double
using PF = void (*)(double); // `using`-based equivalent of the typedef above
using P = [](double)->void; // using plus suffix return type, syntax error
using P = auto(double)->void // Fixed thanks to DyP
Pré-C ++ 11, le using
mot - clé peut amener les fonctions membres dans la portée. En C ++ 11, vous pouvez maintenant le faire pour les constructeurs (un autre exemple de Bjarne Stroustrup):
class Derived : public Base {
public:
using Base::f; // lift Base's f into Derived's scope -- works in C++98
void f(char); // provide a new f
void f(int); // prefer this f to Base::f(int)
using Base::Base; // lift Base constructors Derived's scope -- C++11 only
Derived(char); // provide a new constructor
Derived(int); // prefer this constructor to Base::Base(int)
// ...
};
Ben Voight fournit une assez bonne raison derrière la justification de ne pas introduire un nouveau mot-clé ou une nouvelle syntaxe. La norme veut éviter autant que possible de casser l'ancien code. Voilà pourquoi dans les documents de proposition , vous verrez des sections comme Impact on the Standard
, Design decisions
et comment ils pourraient affecter l' ancien code. Il y a des situations où une proposition semble être une très bonne idée mais pourrait ne pas avoir de traction parce qu'elle serait trop difficile à mettre en œuvre, trop déroutante ou contredirait l'ancien code.
Voici un vieux papier de 2003 n1449 . La justification semble être liée aux modèles. Attention: il peut y avoir des fautes de frappe en raison de la copie depuis un PDF.
Prenons d'abord un exemple de jouet:
template <typename T>
class MyAlloc {/*...*/};
template <typename T, class A>
class MyVector {/*...*/};
template <typename T>
struct Vec {
typedef MyVector<T, MyAlloc<T> > type;
};
Vec<int>::type p; // sample usage
Le problème fondamental de cet idiome, et le principal fait de motivation de cette proposition, est que l'idiome fait apparaître les paramètres du modèle dans un contexte non déductible. Autrement dit, il ne sera pas possible d'appeler la fonction foo ci-dessous sans spécifier explicitement les arguments de modèle.
template <typename T> void foo (Vec<T>::type&);
Donc, la syntaxe est quelque peu moche. Nous préférerions éviter l'imbrication ::type
Nous préférerions quelque chose comme ce qui suit:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Notez que nous évitons spécifiquement le terme «typedef template» et introduisons la nouvelle syntaxe impliquant la paire «using» et «=» pour éviter toute confusion: nous ne définissons aucun type ici, nous introduisons un synonyme (ie alias) pour une abstraction d'un type-id (c'est-à-dire une expression de type) impliquant des paramètres de modèle. Si les paramètres de modèle sont utilisés dans des contextes déductibles dans l'expression de type, chaque fois que l'alias de modèle est utilisé pour former un identifiant de modèle, les valeurs des paramètres de modèle correspondants peuvent être déduites - plus d'informations à ce sujet suivront. Dans tous les cas, il est désormais possible d'écrire des fonctions génériques qui opèrent Vec<T>
dans un contexte déductible, et la syntaxe est également améliorée. Par exemple, nous pourrions réécrire foo comme:
template <typename T> void foo (Vec<T>&);
Nous soulignons ici que l'une des principales raisons de proposer des alias de modèle était que la déduction d'arguments et l'appel à foo(p)
réussissent.
Le document de suivi n1489 explique pourquoi using
au lieu d'utiliser typedef
:
Il a été suggéré de (ré) utiliser le mot-clé typedef - comme cela est fait dans l'article [4] - pour introduire des alias de modèle:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Cette notation a 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 de l'utilisation d'un mot-clé connu pour introduire un alias pour un nom-type dans un contexte où l'alias ne désigne pas un type, mais un modèle; Vec
n'est pas un alias pour un type et ne doit pas être pris pour un typedef-name. Le nom Vec
est un nom pour la famille std::vector< [bullet] , MyAllocator< [bullet] > >
- où la puce est un espace réservé pour un nom de type. Par conséquent, nous ne proposons pas la syntaxe «typedef». D'un autre côté 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 l'aliasing semble raisonnablement logique.
Je pense que la distinction importante est faite ici, alias es au lieu de type s. Une autre citation du même document:
Une déclaration d'alias est une déclaration et non une définition. Une déclaration d'alias introduit un nom dans une région déclarative en tant qu'alias pour le type désigné par le côté droit de la déclaration. Le cœur de cette proposition concerne les alias de nom de type, mais la notation peut évidemment être généralisée pour fournir des orthographes alternatives d'alias d'espace de noms ou d'un ensemble de dénomination de fonctions surchargées (voir ✁ 2.3 pour plus de détails). [ Ma note: cette section traite de ce à quoi cette syntaxe peut ressembler et des raisons pour lesquelles elle ne fait pas partie de la proposition. ] On peut noter que la déclaration d'alias de production de grammaire est acceptable partout où une déclaration typedef ou une définition d'alias d'espace de noms est acceptable.
Résumé, pour le rôle de using
:
- les alias de modèle (ou les typedefs de modèle, le premier étant préféré par nom)
- alias d'espace de nom (c'est-à-dire
namespace PO = boost::program_options
et using PO = ...
équivalent)
- dit le document
A typedef declaration can be viewed as a special case of non-template alias-declaration
. C'est un changement esthétique, et est considéré comme identique dans ce cas.
- mettre quelque chose dans la portée (par exemple,
namespace std
dans la portée globale), fonctions membres, hériter des constructeurs
Il ne peut pas être utilisé pour:
int i;
using r = i; // compile-error
Faites plutôt:
using r = decltype(i);
Nommer un ensemble de surcharges.
// bring cos into scope
using std::cos;
// invalid syntax
using std::cos(double);
// not allowed, instead use Bjarne Stroustrup function pointer alias example
using test = std::cos(double);