2016-05-02 5 views
5

Ich verstehe, dass, wenn eine Ellipse (...) rechts von einem Muster auftritt, das ein Parameterpaket enthält, das Muster für jeden Parameter einmal erweitert wird die Packung. Obwohl ich in der Lage war, vereinzelte Beispiele für Muster mit ihrer Ausdehnung zu finden, war ich nicht in der Lage, eine Definition dessen zu finden, was ein Muster ausmacht. Was ich sehen kann, spielt Whitespace keine Rolle bei der Definition des Musters, aber Klammern tun es. Zum Beispiel in diesem Beispiel:Definition von "pattern" für Erweiterung von Parameterpaketen, besonders innerhalb eines Funktionsaufrufs

template<typename ... Ts> 
void func(Ts) 
{ 
    do_something(validate(Ts)...); 
} 

die do_something Linie würde erweitert werden:

do_something(validate(var1), validate(var2), validate(var3)) 

wenn Ts drei Variablen darstellen passiert ist. Im Gegensatz dazu:

do_something(validate(var1, var2, var3)); 

So klar haben Klammern etwas mit der Bestimmung zu tun, wo das Muster beginnt und endet:

do_something(validate(Ts...)); 

würde erweitert werden. Ich kann auch sehen, dass Whitespace nicht. Aber das bringt mich nur so weit. Ich würde gerne genau wissen, was ein Muster ausmacht und wie es erweitert wird. Ich habe versucht, den C++ Standard zu durchsuchen, habe aber zu viele Instanzen von "Parameter Packs" gefunden, um das zu erreichen. Könnte mir bitte jemand eine Definition von "Muster" oder einen Link zu einer Definition oder beides geben?

UPDATE: Um den Umfang meiner Frage zu begrenzen, möchte ich auf den Fall konzentrieren, wo ein Muster innerhalb eines Funktionsaufrufs auftritt. Ich habe den Titel entsprechend bearbeitet. Tut mir leid, ich habe das nicht von Anfang an klargestellt.

+2

[Dies] (http://en.cppreference.com/w/cpp/language/parameter_pack) hat nicht geholfen? – NathanOliver

+0

@NathanOliver, nein, diese cppreference.com-Seite ist eine von vielen, die sich auf Muster bezieht, ohne jemals zu definieren, was ein Muster ist. – Alan

+0

http://eel.is/c++draft/temp.variadic#4 –

Antwort

7

A Muster ist in der Norm unter [temp.variadic]/4 definiert: (via @t.c.)

A Erweiterungspaket ein Muster besteht und ein Auslassungszeichen, die Instanziierung davon erzeugt null oder mehr Instanziierungen des Musters in einer Liste (unten beschrieben). Die Form des Musters hängt vom Kontext ab, in dem die Erweiterung stattfindet.Paketerweiterungen können in den folgenden Kontexten auftreten:

Das obige Zitat aus dem Standardentwurf spricht über das, was Teil der Grammatik in den Links beschrieben ist das „Muster“, das erweitert wird. Um es zu verstehen, müssen Sie wissen, wie die C++ - Grammatik beschrieben ist, und die Ausnahmen, wie sie im Standardtext selbst verwendet werden; Wenn Sie jedoch grundlegendes BNF-Wissen und ein wenig Geduld haben, können Sie es erarbeiten. Die Namen sind oft auch nützlich.


Sie können jedoch ... verwenden und vor allem verstehen es fast so tief, ohne dabei.

Die allgemeine Regel ist einfach: Sie etwas wenig C++ Grammatik (die so genannten Muster) auf die übliche Art und Weise analysiert, wobei ein Satz von Typen wie eine einzige Art behandelt wird, und eine Packung von Literalen ist behandelt wie ein einzelnes Literal. Dann, am Ende davon, haben Sie einen ... Expander.Es nimmt dann alle unexpanded Packs in das Bit der C++ - Grammatik unmittelbar vor (das Muster) und erweitert es.

Wie dies in jedem Kontext funktioniert, ist anders; es ist nicht nur eine Makroerweiterung. Die Kontexte, in denen ... gültig ist, sind oben aufgezählt; Die Auswirkungen der Erweiterung sind im Standard an jedem Punkt aufgeführt, an dem sie gültig sind.

In den banalsten Anwendungsfällen von ..., ist das Muster ein Ausdruck, und der Ausdruck erweitert wird als-ob es jeweils durch , getrennt Kopie (nicht operator,, aber die anderen „normale“ ein), in der Regel in einem Kontext, in dem eine Liste von Dingen erwartet wird (Funktionsaufruf, Initialisierungsliste usw.).

Es gibt Funktionsparameter Deklaration Kontexten (wo ... sowohl die Typen der Funktionsparameter erweitert und stellt eine neue Packung der Paramter Namen), in Template-Parameter-Listen (wo es in der Regel eine Packung einführt) usw.

sizeof... ist ein bisschen seltsam: für sizeof... zählt, wie viele Elemente in der Packung in der () übergeben werden. Dies funktioniert anders, da sich die ... nicht auf die "Struktur auf der linken Seite" bezieht.

Für alignas(X...) beenden wir mit alignas([email protected]), alignas([email protected]), ... oben (wo @0 mein Pseudo-Code für das erste Element des Pakets ist), als alignas([email protected], [email protected], ...) nicht gültig C++ (wieder @ T. C. In den Kommentaren unten).

Für die Vererbung wird eine Reihe von Basisklassen erstellt. Für mem-initializer-lists können Sie ctor-Argumente an das Paket von Basisklassen übergeben. Für lambdas gibt es eine begrenzte Erfassung von Packs (nicht voll bei Ausdruckserfassung mit der zuletzt von mir überprüften Erweiterung).

Das Muster ist die Sache erweitert. Wichtig ist, dass ein erweitertes Muster nicht durch einen anderen Musterexpander erweitert wird: so ist std::array< Ts, sizeof...(Ts) >... ein Paket von Arrays verschiedener Typen, jedes mit einer Anzahl von Elementen, die dadurch bestimmt wird, wie groß das Paket selbst ist. sizeof...(Ts) "zählt als Erweiterung" die Ts in seiner (), obwohl ... ist nicht "richtig", weil die Sprache definiert Ts in der () als das Muster, das durch die ... erweitert wird.

Das Muster im allgemeinen Fall kann nicht als Ausdruck bezeichnet werden, da Typen keine Ausdrücke sind und einige Muster Ausdrücke sind (oder zumindest in Listen von Ausdrücken auftauchen). Und in einigen Fällen erweitert ... ein type-pattern in ein erweitertes Paket von Typen (wie im throw-Ausdruck).

Die allgemeine Regel, dass Sie ... als Erweiterung das Ding auf der linken Seite in geeigneter Weise im lokalen Kontext behandeln, arbeitet für fast alles außer sizeof... (was ein magischer Operator ist, dass Sie, wie viele Elemente in einem Parameter erzählt Pack). Es wird nur in Eckfällen sein, wo dies kein anständiges Modell hervorbringt. Und nach meiner Erfahrung wird es im schlimmsten Fall zu Code führen, der nicht kompiliert, wenn Sie denken, dass er es sollte; In diesem Fall können Sie Workarounds lernen. Denken Sie daran, dass eine nackte Aussage "keinen lokalen Kontext hat", so dass Sie nicht die (void)(int[]){0,(a = std::get<Is>(tup)),0)...}; (möglicherweise int[]) tun müssen, wo wir einen Kontext (Erstellen eines Arrays) für die Pack-Erweiterung zur Verfügung stellen .

C++ 1z Falte Ausdrücke sind eine andere schrullige Stelle, wo ... gilt nicht auf der linken Seite; hier wollten sie eine Erweiterung eines binären Operators haben, so dass "links" nicht so viel Sinn macht wie die übliche "unäre" Erweiterung.

+0

Eine dritte schrullige Stelle ist 'alignas'. 'alignas (Ts ...)' ist äquivalent zu 'alignas (T0) alignas (T1) ... alignas (TN) ', nicht' alignas (T0, T1, ... TN)' (was nicht gilt) obwohl es ein offenes EWG-Problem gibt, um es zu ändern. –

+0

Wenn Sie sagen "Das Muster kann nicht als Ausdruck bezeichnet werden, weil Typen keine Ausdrücke sind", meinen Sie vielleicht "Das Muster kann IMMER nicht als Ausdruck bezeichnet werden"? Es scheint, dass in einem Funktionsaufruf das Muster tatsächlich ein Ausdruck ist. – Alan

+0

@Alan sicher, aber der Begriff im Standard, der das Muster umfasst, kann nicht "der Ausdruck" genannt werden, da Ausdruck eine Bedeutung in C++ hat. Es wäre so, als würde man im Allgemeinen über Funktionsparameter reden, indem man speziell über "int" -Parameter spricht. – Yakk

0

Das Muster wird durch seine Zuordnung zur Erweiterungssyntax ... definiert. So ist validate(ts) allein nur ein Fragment von bedeutungslosem Text. Aber validate(ts)... macht den validate(ts) Teil das Muster der Erweiterung. Es hängt also davon ab, wie sich der zugehörige Code auf ... auswirkt.

In der Regel bezeichnet Entpacksyntax, dass das Zeug auf der linken Seite der ... das Muster ist. Mit den Falteausdrücken von C++ 17 wird dies etwas komplexer. Aber im Allgemeinen, wenn Sie wissen wollen, was das Muster ist, finden Sie die ..., und schauen Sie sich den Ausdruck direkt links davon an.

Die spezifischen Einschränkungen, die in dem Muster enthalten sein können, hängen vollständig davon ab, wo die Erweiterung stattfindet und welche Art von Paket betroffen ist (Typ vs. Nicht-Typ usw.). Das Muster muss sein, was auch immer der rechtliche Code für welchen Kontext auch immer sein würde.

Verwandte Themen