In C ++ 11, la using
parola chiave quando utilizzata type alias
è identica a typedef
.
7.1.3.2
Un nome typedef può anche essere introdotto da una dichiarazione alias. L'identificatore che segue la parola chiave using diventa un typedef-name e l'attributo-specificifier-seq che segue l'identificatore appartiene a quel typedef-name. Ha la stessa semantica come se fosse stata introdotta dallo specificatore typedef. In particolare, non definisce un nuovo tipo e non deve apparire nell'identificativo.
Bjarne Stroustrup fornisce un esempio pratico:
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
Pre-C ++ 11, la using
parola chiave può portare le funzioni membro nell'ambito. In C ++ 11, ora puoi farlo per i costruttori (un altro esempio di 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 fornisce una ragione abbastanza valida dietro la logica di non introdurre una nuova parola chiave o una nuova sintassi. Lo standard vuole evitare di rompere il vecchio codice il più possibile. Questo è il motivo per cui nei documenti di proposta si vedrà sezioni come Impact on the Standard
, Design decisions
e come potrebbero influenzare vecchio codice. Ci sono situazioni in cui una proposta sembra davvero una buona idea ma potrebbe non avere una trazione perché sarebbe troppo difficile da implementare, troppo confusa o contraddirebbe il vecchio codice.
Ecco un vecchio documento del 2003 n . 1449 . La logica sembra essere correlata ai modelli. Attenzione: potrebbero esserci errori di battitura a causa della copia da PDF.
Per prima cosa consideriamo un esempio di giocattolo:
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
Il problema fondamentale con questo linguaggio, e il principale fatto motivante per questa proposta, è che il linguaggio fa apparire i parametri del modello in un contesto non deducibile. Cioè, non sarà possibile chiamare la funzione foo sotto senza specificare esplicitamente gli argomenti del template.
template <typename T> void foo (Vec<T>::type&);
Quindi, la sintassi è piuttosto brutta. Preferiremmo evitare il nidificato ::type
Preferiremmo qualcosa di simile al seguente:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Si noti che evitiamo in modo specifico il termine "modello typedef" e introduciamo la nuova sintassi che coinvolge la coppia "using" e "=" per evitare confusione: non stiamo definendo alcun tipo qui, stiamo introducendo un sinonimo (ovvero alias) per un'astrazione di un id-tipo (cioè espressione di tipo) che coinvolge parametri di template. Se i parametri del modello vengono utilizzati in contesti deducibili nell'espressione del tipo, ogni volta che viene utilizzato l'alias del modello per formare un ID modello, i valori dei parametri del modello corrispondente possono essere dedotti - ne seguiranno altri. In ogni caso, ora è possibile scrivere funzioni generiche che operano Vec<T>
in un contesto deducibile e anche la sintassi è migliorata. Ad esempio, potremmo riscrivere foo come:
template <typename T> void foo (Vec<T>&);
Sottolineiamo qui che uno dei motivi principali per proporre alias modello è stato che la deduzione degli argomenti e la chiamata a foo(p)
riuscissero.
Il documento di follow-up n1489 spiega perché using
invece di usare typedef
:
È stato suggerito di (ri) usare la parola chiave typedef - come fatto nel documento [4] - per introdurre alias di template:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Tale notazione ha il vantaggio di utilizzare una parola chiave già nota per introdurre un alias di tipo. Tuttavia, mostra anche diversi svantaggi tra cui la confusione dell'uso di una parola chiave nota per introdurre un alias per un tipo-nome in un contesto in cui l'alias non designa un tipo, ma un modello; Vec
non è un alias per un tipo e non dovrebbe essere preso per un nome typedef. Il nome Vec
è un nome per la famiglia std::vector< [bullet] , MyAllocator< [bullet] > >
, in cui il punto elenco è un segnaposto per un tipo-nome. Di conseguenza non proponiamo la sintassi "typedef". D'altra parte la frase
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
può essere letto / interpretato come: da ora in poi, userò Vec<T>
come sinonimo di std::vector<T, MyAllocator<T> >
. Con quella lettura, la nuova sintassi per l'aliasing sembra ragionevolmente logica.
Penso che l'importante distinzione sia fatta qui, alias es invece del tipo s. Un'altra citazione dallo stesso documento:
Una dichiarazione alias è una dichiarazione e non una definizione. Una dichiarazione alias introduce un nome in una regione dichiarativa come alias per il tipo designato dal lato destro della dichiarazione. Il nucleo di questa proposta riguarda gli alias dei nomi di tipo, ma la notazione può ovviamente essere generalizzata per fornire ortografia alternativa di alias dello spazio dei nomi o set di nomi di funzioni sovraccariche (vedere ✁ 2.3 per ulteriori discussioni). [ Nota mia: in questa sezione vengono illustrati l'aspetto della sintassi e i motivi per cui non fa parte della proposta. ] Si può notare che la dichiarazione di alias di produzione grammaticale è accettabile ovunque sia accettabile una dichiarazione di battitura a macchina o una definizione di alias di spazio dei nomi.
Riepilogo, per il ruolo di using
:
- alias modello (o typedef modello, il primo è preferito per nome)
- alias namespace (cioè,
namespace PO = boost::program_options
e using PO = ...
equivalenti)
- dice il documento
A typedef declaration can be viewed as a special case of non-template alias-declaration
. È un cambiamento estetico ed è considerato identico in questo caso.
- portando qualcosa nel campo di applicazione (ad esempio,
namespace std
nel campo di applicazione globale), funzioni membro, ereditando costruttori
Non può essere utilizzato per:
int i;
using r = i; // compile-error
Invece fai:
using r = decltype(i);
Denominare una serie di sovraccarichi.
// 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);