Die folgenden Informationen sind veraltet. Es muss gemäß dem neuesten Entwurf von Concepts Lite aktualisiert werden.
Abschnitt 3 des Beschränkungsvorschlags behandelt dies in angemessener Tiefe.
Der Konzeptvorschlag wurde für kurze Zeit in den Hintergrund gedrängt, in der Hoffnung, dass Einschränkungen (dh Concepts-Lite) in kürzerer Zeit konkretisiert und implementiert werden können, wobei derzeit zumindest etwas in C ++ 14 angestrebt wird. Der Einschränkungsvorschlag soll als reibungsloser Übergang zu einer späteren Definition von Konzepten dienen. Einschränkungen sind Teil des Konzeptvorschlags und ein notwendiger Baustein in seiner Definition.
Bei der Gestaltung von Konzeptbibliotheken für C ++ berücksichtigen Sutton und Stroustrup die folgende Beziehung:
Konzepte = Einschränkungen + Axiome
Um ihre Bedeutung schnell zusammenzufassen:
- Einschränkung - Ein Prädikat über statisch auswertbare Eigenschaften eines Typs. Rein syntaktische Anforderungen. Keine Domain-Abstraktion.
- Axiome - Semantische Anforderungen von Typen, von denen angenommen wird, dass sie wahr sind. Nicht statisch geprüft.
- Konzepte - Allgemeine, abstrakte Anforderungen von Algorithmen an ihre Argumente. Definiert in Bezug auf Einschränkungen und Axiome.
Wenn Sie also Einschränkungen (syntaktische Eigenschaften) Axiome (semantische Eigenschaften) hinzufügen, erhalten Sie Konzepte.
Concepts-Lite
Der Concepts-Lite-Vorschlag bringt uns nur den ersten Teil, Einschränkungen, aber dies ist ein wichtiger und notwendiger Schritt in Richtung vollwertiger Konzepte.
Einschränkungen
Bei Einschränkungen dreht sich alles um Syntax . Sie bieten uns die Möglichkeit, Eigenschaften eines Typs zur Kompilierungszeit statisch zu erkennen, sodass wir die als Vorlagenargumente verwendeten Typen basierend auf ihren syntaktischen Eigenschaften einschränken können. Im aktuellen Vorschlag für Einschränkungen werden sie mit einer Teilmenge der Satzrechnung unter Verwendung logischer Verknüpfungen wie &&
und ausgedrückt ||
.
Werfen wir einen Blick auf eine Einschränkung in Aktion:
template <typename Cont>
requires Sortable<Cont>()
void sort(Cont& container);
Hier definieren wir eine Funktionsvorlage namens sort
. Der Neuzugang ist die require-Klausel . Die require-Klausel enthält einige Einschränkungen für die Vorlagenargumente für diese Funktion. Diese Einschränkung besagt insbesondere, dass der Typ Cont
ein Sortable
Typ sein muss. Eine nette Sache ist, dass es in einer prägnanteren Form geschrieben werden kann als:
template <Sortable Cont>
void sort(Cont& container);
Wenn Sie nun versuchen, etwas zu übergeben, das Sortable
für diese Funktion nicht berücksichtigt wurde , wird eine nette Fehlermeldung angezeigt, die Sie sofort darüber informiert, dass der abgeleitete Typ T
kein Sortable
Typ ist. Wenn Sie dies in C ++ 11 getan hätten, wäre in der sort
Funktion ein schrecklicher Fehler aufgetreten , der für niemanden Sinn macht.
Constraints-Prädikate sind Typmerkmalen sehr ähnlich. Sie nehmen einen Vorlagenargumenttyp und geben Ihnen einige Informationen darüber. Einschränkungen versuchen, die folgenden Arten von Fragen zum Typ zu beantworten:
- Hat dieser Typ den einen oder anderen Operator überladen?
- Können diese Typen als Operanden für diesen Operator verwendet werden?
- Hat dieser Typ das eine oder andere Merkmal?
- Ist dieser konstante Ausdruck gleich dem? (für nicht typisierte Vorlagenargumente)
- Hat dieser Typ eine Funktion namens yada-yada, die diesen Typ zurückgibt?
- Erfüllt dieser Typ alle syntaktischen Anforderungen, die als solcher verwendet werden sollen?
Einschränkungen sollen jedoch keine Typmerkmale ersetzen . Stattdessen arbeiten sie Hand in Hand. Einige Typmerkmale können jetzt in Form von Konzepten und einige Konzepte in Form von Typmerkmalen definiert werden.
Beispiele
Das Wichtige an Einschränkungen ist also, dass sie sich nicht um die Semantik ein Jota kümmern. Einige gute Beispiele für Einschränkungen sind:
Equality_comparable<T>
: Überprüft, ob der Typ ==
mit beiden Operanden desselben Typs hat.
Equality_comparable<T,U>
: Überprüft, ob es einen ==
mit linken und rechten Operanden des angegebenen Typs gibt
Arithmetic<T>
: Überprüft, ob der Typ ein arithmetischer Typ ist.
Floating_point<T>
: Überprüft, ob der Typ ein Gleitkommatyp ist.
Input_iterator<T>
: Überprüft, ob der Typ die syntaktischen Operationen unterstützt, die ein Eingabe-Iterator unterstützen muss.
Same<T,U>
: Überprüft, ob der angegebene Typ identisch ist.
Sie können dies alles mit einem speziellen Concept-Lite-Build von GCC ausprobieren .
Jenseits von Concepts-Lite
Jetzt kommen wir zu allem, was über den Konzept-Lite-Vorschlag hinausgeht. Dies ist noch futuristischer als die Zukunft selbst. Alles von hier an wird sich wahrscheinlich ziemlich ändern.
Axiome
In Axiomen dreht sich alles um Semantik . Sie spezifizieren Beziehungen, Invarianten, Komplexitätsgarantien und andere solche Dinge. Schauen wir uns ein Beispiel an.
Während die Equality_comparable<T,U>
Einschränkung wird Ihnen sagen , dass es eine ist , operator==
die Arten nimmt T
und U
es wird Ihnen nicht sagen , was das Betrieb Mittel . Dafür werden wir das Axiom haben Equivalence_relation
. Dieses Axiom besagt, dass wenn Objekte dieser beiden Typen mit dem operator==
Geben verglichen werden true
, diese Objekte äquivalent sind. Dies mag überflüssig erscheinen, ist es aber sicherlich nicht. Sie können leicht eine definieren operator==
, die sich stattdessen wie eine verhält operator<
. Du wärst böse, das zu tun, aber du könntest.
Ein anderes Beispiel ist ein Greater
Axiom. Es ist alles schön und gut zu sagen , zwei Objekte vom Typ im T
Vergleich zu können >
und <
Betreibern, aber was sie bedeuten ? Das Greater
Axiom sagt, wenn iff x
größer ist y
, dann y
ist kleiner als x
. Die vorgeschlagene Spezifikation eines solchen Axioms sieht aus wie:
template<typename T>
axiom Greater(T x, T y) {
(x>y) == (y<x);
}
Axiome beantworten also die folgenden Arten von Fragen:
- Haben diese beiden Operatoren diese Beziehung zueinander?
- Bedeutet dieser Operator für den einen oder anderen Typ dies?
- Hat diese Operation für diesen Typ diese Komplexität?
- Bedeutet dieses Ergebnis dieses Operators, dass dies wahr ist?
Das heißt, sie befassen sich ausschließlich mit der Semantik von Typen und Operationen für diese Typen. Diese Dinge können nicht statisch überprüft werden. Wenn dies überprüft werden muss, muss ein Typ in irgendeiner Weise verkünden, dass er dieser Semantik entspricht.
Beispiele
Hier sind einige gängige Beispiele für Axiome:
Equivalence_relation
: Wenn zwei Objekte verglichen werden ==
, sind sie gleichwertig.
Greater
: Wann immer x > y
dann y < x
.
Less_equal
: Wann immer x <= y
dann !(y < x)
.
Copy_equality
: Für x
und y
vom Typ T
: if x == y
, ein neues Objekt desselben Typs, das durch Kopierkonstruktion erstellt wurde T{x} == y
und dennoch x == y
(dh es ist nicht destruktiv).
Konzepte
Jetzt sind Konzepte sehr einfach zu definieren. Sie sind einfach die Kombination von Zwängen und Axiomen . Sie bieten eine abstrakte Anforderung an die Syntax und Semantik eines Typs.
Betrachten Sie als Beispiel das folgende Ordered
Konzept:
concept Ordered<Regular T> {
requires constraint Less<T>;
requires axiom Strict_total_order<less<T>, T>;
requires axiom Greater<T>;
requires axiom Less_equal<T>;
requires axiom Greater_equal<T>;
}
Zunächst ist zu beachten , dass für den Template - Typen T
sein Ordered
, es muss auch die Anforderungen des gerecht Regular
Konzepts. Das Regular
Konzept ist eine sehr grundlegende Voraussetzung dafür, dass sich der Typ gut verhält - er kann konstruiert, zerstört, kopiert und verglichen werden.
Zusätzlich zu den Anforderungen, die Ordered
erfordern , dass T
erfüllen eine Einschränkung und vier Axiome:
- Einschränkung: Ein
Ordered
Typ muss eine haben operator<
. Dies wird statisch überprüft, sodass es vorhanden sein muss .
- Axiome: Für
x
und y
vom Typ T
:
x < y
gibt eine strikte Gesamtbestellung.
- Wann
x
ist größer als y
, y
ist kleiner als x
und umgekehrt.
- Wenn
x
kleiner oder gleich ist y
, y
ist nicht kleiner als x
und umgekehrt.
- Wenn
x
größer oder gleich ist y
, y
ist nicht größer als x
und umgekehrt.
Wenn Sie solche Einschränkungen und Axiome kombinieren, erhalten Sie Konzepte. Sie definieren die syntaktischen und semantischen Anforderungen für abstrakte Typen zur Verwendung mit Algorithmen. Algorithmen müssen derzeit davon ausgehen, dass die verwendeten Typen bestimmte Operationen unterstützen und bestimmte Semantiken ausdrücken. Mit Konzepten können wir sicherstellen, dass die Anforderungen erfüllt werden.
Im neuesten Konzeptentwurf überprüft der Compiler nur, ob die syntaktischen Anforderungen eines Konzepts durch das Vorlagenargument erfüllt werden. Die Axiome bleiben unkontrolliert. Da Axiome Semantiken bezeichnen, die nicht statisch auswertbar sind (oder oft nicht vollständig überprüft werden können), müsste der Autor eines Typs explizit angeben, dass sein Typ alle Anforderungen eines Konzepts erfüllt. Dies war in früheren Entwürfen als Concept Mapping bekannt, wurde jedoch inzwischen entfernt.
Beispiele
Hier einige Beispiele für Konzepte:
Regular
Typen sind konstruierbar, zerstörbar, kopierbar und können verglichen werden.
Ordered
Typen unterstützen operator<
und haben eine strikte Gesamtreihenfolge und andere Ordnungssemantik.
Copyable
Typen sind kopierkonstruierbar, zerstörbar, und wenn sie x
gleich sind y
und x
kopiert werden, wird die Kopie auch gleich verglichen y
.
Iterator
Typen müssen zugeordnet Typen haben value_type
, reference
, difference_type
, und iterator_category
die müssen sich bestimmte Konzepte erfüllen. Sie müssen auch unterstützen operator++
und dereferenzierbar sein.
Der Weg zu Konzepten
Einschränkungen sind der erste Schritt in Richtung einer vollständigen Konzeptfunktion von C ++. Sie sind ein sehr wichtiger Schritt, da sie die statisch durchsetzbaren Anforderungen von Typen bereitstellen, damit wir viel sauberere Vorlagenfunktionen und -klassen schreiben können. Jetzt können wir einige der Schwierigkeiten und Hässlichkeiten std::enable_if
seiner und seiner Metaprogrammierfreunde vermeiden .
Es gibt jedoch eine Reihe von Dingen, die der Vorschlag für Einschränkungen nicht tut:
Es bietet keine Konzeptdefinitionssprache.
Einschränkungen sind keine Konzeptkarten. Der Benutzer muss seine Typen nicht speziell mit Anmerkungen versehen, um bestimmte Einschränkungen zu erfüllen. Sie werden statisch überprüft, indem einfache Sprachfunktionen zur Kompilierungszeit verwendet werden.
Die Implementierungen von Vorlagen sind nicht durch die Einschränkungen ihrer Vorlagenargumente eingeschränkt. Das heißt, wenn Ihre Funktionsvorlage mit einem Objekt vom eingeschränkten Typ etwas tut, was sie nicht tun sollte, hat der Compiler keine Möglichkeit, dies zu diagnostizieren. Ein voll ausgestatteter Konzeptvorschlag wäre dazu in der Lage.
Der Einschränkungsvorschlag wurde speziell so konzipiert, dass zusätzlich ein vollständiger Konzeptvorschlag eingeführt werden kann. Mit etwas Glück sollte dieser Übergang ziemlich reibungslos verlaufen. Die Konzeptgruppe versucht, Einschränkungen für C ++ 14 (oder kurz darauf in einem technischen Bericht) einzuführen, während irgendwann um C ++ 17 herum vollständige Konzepte auftauchen könnten.