In C ++ 11 ist das using
Schlüsselwort bei Verwendung für type alias
identisch mit typedef
.
7.1.3.2
Ein typedef-Name kann auch durch eine Alias-Deklaration eingeführt werden. Der Bezeichner nach dem Schlüsselwort using wird zu einem typedef-Namen, und der optionale Attributbezeichner-seq nach dem Bezeichner gehört zu diesem typedef-Namen. Es hat dieselbe Semantik, als ob es vom typedef-Spezifizierer eingeführt worden wäre. Insbesondere definiert es keinen neuen Typ und darf nicht in der Typ-ID erscheinen.
Bjarne Stroustrup bietet ein praktisches Beispiel:
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
Vor C ++ 11 kann das using
Schlüsselwort Mitgliedsfunktionen in den Geltungsbereich bringen. In C ++ 11 können Sie dies jetzt für Konstruktoren tun (ein weiteres Beispiel von 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 liefert einen ziemlich guten Grund für die Begründung, kein neues Schlüsselwort oder keine neue Syntax einzuführen. Der Standard möchte vermeiden, dass alter Code so weit wie möglich beschädigt wird. Aus diesem Grunde ist in den Vorschlägen werden Sie Abschnitte sehen mögen Impact on the Standard
, Design decisions
und wie sie könnten älteren Code beeinflussen. Es gibt Situationen, in denen ein Vorschlag eine wirklich gute Idee zu sein scheint, aber möglicherweise keine Wirkung hat, weil er zu schwierig zu implementieren, zu verwirrend oder dem alten Code zuwiderlaufen würde.
Hier ist ein altes Papier aus dem Jahr 2003 n1449 . Die Begründung scheint mit Vorlagen zu zusammenhängen. Warnung: Beim Kopieren aus PDF können Tippfehler auftreten.
Betrachten wir zunächst ein Spielzeugbeispiel:
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
Das grundlegende Problem mit dieser Redewendung und die Hauptmotivation für diesen Vorschlag besteht darin, dass die Redewendung bewirkt, dass die Vorlagenparameter in einem nicht ableitbaren Kontext erscheinen. Das heißt, es ist nicht möglich, die folgende Funktion foo aufzurufen, ohne explizit Vorlagenargumente anzugeben.
template <typename T> void foo (Vec<T>::type&);
Die Syntax ist also etwas hässlich. Wir möchten lieber die verschachtelten vermeiden. ::type
Wir würden Folgendes bevorzugen:
template <typename T>
using Vec = MyVector<T, MyAlloc<T> >; //defined in section 2 below
Vec<int> p; // sample usage
Beachten Sie, dass wir den Begriff „typedef template“ ausdrücklich vermeiden und die neue Syntax für das Paar „using“ und „=“ einführen, um Verwirrung zu vermeiden: Wir definieren hier keine Typen, sondern führen ein Synonym (dh einen Alias) für ein eine Abstraktion einer Typ-ID (dh eines Typausdrucks) mit Vorlagenparametern. Wenn die Vorlagenparameter in ableitbaren Kontexten im Typausdruck verwendet werden, können die Werte der entsprechenden Vorlagenparameter abgeleitet werden, wenn der Vorlagenalias zur Bildung einer Vorlagen-ID verwendet wird. Weitere Informationen hierzu folgen. In jedem Fall ist es jetzt möglich, generische Funktionen zu schreiben, die Vec<T>
in einem ableitbaren Kontext ausgeführt werden, und die Syntax wird ebenfalls verbessert. Zum Beispiel könnten wir foo wie folgt umschreiben:
template <typename T> void foo (Vec<T>&);
Wir unterstreichen hier, dass einer der Hauptgründe für das Vorschlagen von Vorlagenaliasnamen darin bestand, dass die Argumentableitung und der Aufruf zu foo(p)
erfolgreich sein werden.
Das Folgepapier n1489 erklärt, warum using
anstelle von typedef
:
Es wurde vorgeschlagen, das Schlüsselwort typedef (wie in diesem Artikel [4] beschrieben) (erneut) zu verwenden, um Vorlagen-Aliase einzuführen:
template<class T>
typedef std::vector<T, MyAllocator<T> > Vec;
Diese Notation hat den Vorteil, dass ein Schlüsselwort verwendet wird, von dem bereits bekannt ist, dass es einen Typalias einführt. Es werden jedoch auch einige Nachteile angezeigt, darunter die Verwirrung bei der Verwendung eines Schlüsselworts, von dem bekannt ist, dass es einen Alias für einen Typnamen in einem Kontext einführt, in dem der Alias keinen Typ, sondern eine Vorlage angibt. Vec
ist kein Alias für einen Typ und sollte nicht für einen typedef-Namen verwendet werden. Der Name Vec
ist ein Name für die Familie std::vector< [bullet] , MyAllocator< [bullet] > >
- wobei das Aufzählungszeichen ein Platzhalter für einen Typnamen ist. Folglich schlagen wir die "typedef" -Syntax nicht vor. Auf der anderen Seite der Satz
template<class T>
using Vec = std::vector<T, MyAllocator<T> >;
kann gelesen / interpretiert werden als: von nun an werde ich Vec<T>
als Synonym für verwenden std::vector<T, MyAllocator<T> >
. Mit dieser Lesart erscheint die neue Syntax für Aliasing ziemlich logisch.
Ich denke, hier wird die wichtige Unterscheidung getroffen, alias es statt type s. Ein weiteres Zitat aus demselben Dokument:
Eine Alias-Deklaration ist eine Deklaration und keine Definition. Eine Alias-Deklaration führt einen Namen in einen deklarativen Bereich als Alias für den Typ ein, der auf der rechten Seite der Deklaration angegeben ist. Der Kern dieses Vorschlags befasst sich mit Typnamen-Aliasnamen, aber die Notation kann offensichtlich verallgemeinert werden, um alternative Schreibweisen für Namespace-Aliasing oder die Benennung von überladenen Funktionen bereitzustellen (siehe ✁ 2.3 für weitere Erläuterungen). [ Mein Hinweis: In diesem Abschnitt wird erläutert, wie diese Syntax aussehen kann und warum sie nicht Teil des Vorschlags ist. ] Es kann angemerkt werden, dass die Grammatikproduktions-Alias-Deklaration überall dort akzeptabel ist, wo eine typedef-Deklaration oder eine Namespace-Alias-Definition akzeptabel ist.
Zusammenfassung für die Rolle von using
:
- Template-Aliase (oder Template-Typedefs, ersteres wird namentlich bevorzugt)
- Namespace-Aliase (dh
namespace PO = boost::program_options
und using PO = ...
gleichwertig)
- das Dokument sagt
A typedef declaration can be viewed as a special case of non-template alias-declaration
. Es ist eine ästhetische Veränderung und wird in diesem Fall als identisch angesehen.
- etwas in den Geltungsbereich bringen (zum Beispiel
namespace std
in den globalen Geltungsbereich), Elementfunktionen, Konstruktoren erben
Es kann nicht verwendet werden für:
int i;
using r = i; // compile-error
Tun Sie stattdessen:
using r = decltype(i);
Benennen einer Reihe von Überladungen.
// 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);