iX 12/2017
S. 48
Titel
Programmiersprachen I
Aufmacherbild

Concepts in C++20: Die zentralen Ideen

Revolutionäre Gedanken

Concepts sind eine Erweiterung der Templates von C++, mit denen man semantische Kategorien für die Menge der zulässigen Datentypen definieren kann. Sie sollen endlich Teil der Spezifikation sein.

Die zentrale Idee der generischen Programmierung mit Templates in C++ ist es, Funktionen und Klassen zu definieren, die man mit verschiedenen Typen verwenden kann. Oft kommt es aber vor, dass ein Template mit einem ungeeigneten Typ instanziiert wird. Das Ergebnis sind dann oft seitenlange, kryptische Fehlermeldungen, für die Templates traurige Berühmtheit erlangt haben.

Damit räumen Concepts auf, denn sie ermöglichen es, Anforderungen an Templates zu stellen, die der Compiler verifiziert. Concepts bieten aber noch viel mehr an. Sie werden die Art und Weise revolutionieren, wie Programmierer über generischen Code (Templates) in C++ denken und ihn schreiben. Von dieser Revolution in C++20 handeln dieser und der Artikel auf Seite 54.

Ein erster, schneller Überblick

Concepts stellen in erster Annäherung den Mittelweg zwischen zwei Extremen dar. Einerseits verwenden C++-Programmierer Funktionen und Klassen, die für konkrete Datentypen konzipiert sind. Andererseits nutzen sie Familien von Funktionen (Funktions-Templates) und Familien von Klassen (Klassen-Templates), die potenziell alle Datentypen annehmen können. Concepts erlauben es, semantische Kategorien für die Menge der zulässigen Datentypen für ein Funktions- oder Klassen-Template zu definieren. Unter semantische Kategorien fallen etwa solche wie Gleichheit, Ordnung oder auch mathematische Klassifizierungen wie Integral oder Real. Im Einzelnen heißt das:

 Anforderungen an die Templates lassen sich als Teil des Interface formulieren.

 Das Überladen von Funktionen und die Spezialisierung von Klassen-Templates sind aufgrund der Anforderungen an die Templates möglich.

 Der Compiler erzeugt deutlich verbesserte Fehlermeldungen, da er diese Anforderungen an die Template-Parameter mit den aktuellen Template-Argumenten prüft.

Das ist aber erst der Anfang der Revolution. Es geht weiter:

 Programmierer können eigene Concepts definieren und bestehende verfeinern.

 Die Syntax der automatischen Typableitung mit auto und Concepts wird vereinheitlicht. Konkret heißt das, dass man anstelle des Schlüsselwortes auto direkt ein Concept wie Gleichheit verwenden kann. Damit ist der vom Compiler automatisch abgeleitete Datentyp nur dann zulässig, wenn er das Concept Gleichheit unterstützt.

 Ist ein Concept Ordnung Parameter einer Funktion, wird diese Funktion automatisch zum Funktions-Template. Dieses fordert nun, dass seine Argumente einer Ordnung folgen.

Diesen deutlichen Mehrwert gibt es ohne eine längere Übersetzungs- oder Laufzeit des Programms. Inspiriert sind Concepts durch Haskells Typklassen. Ein Blick über den Tellerrand in Haskells Typklassen zeigt deren Eleganz und Mächtigkeit – und damit auch die von Concepts.

Kleiner Ausflug in Haskells Typklassen

Haskells Typklassen sind Interfaces für ähnliche Typen und stehen in hierarchischer Abhängigkeit zueinander (Abb. 1).

Typklassen sind Interfaces für ähnliche Typen. Ist ein Datentyp Mitglied einer Typklasse, bietet er bestimmte Eigenschaften an. Typklassen erfüllen für die generische Programmierung eine ähnliche Rolle wie Interfaces für die objektorientierte. Abbildung 1 zeigt einen Teil der Typklassenhierarchie Haskells.

Im Fall von Datentypen, die Mitglied der Typklasse Eq sind, steht Eq für Gleichheit (Equality) und stellt folgende Anforderung an seine Mitglieder:

class Eq a where 
    (==) :: a -> a -> Bool 
    (/=) :: a -> a -> Bool 
    a == b = not (a /= b) 
    a /= b = not (a == b) 

Eq fordert, dass seine Datentypen jeweils eine Funktion Gleichheit (==) und Ungleichheit (/=) anbieten. Der Ausdruck a -> a -> Bool beschreibt die Signatur der Funktion. Sie erwartet zwei gleiche Datentypen a und gibt einen Wahrheitswert Bool zurück. Tatsächlich reicht es aber aus, für einen Datentyp Gleichheit oder Ungleichheit zu definieren, da Gleichheit durch Ungleichheit, Ungleichheit durch Gleichheit definiert werden kann. Die Default-Implementierungen für Gleichheit und Ungleichheit sind bereits in den letzten zwei Zeilen vorhanden. Die folgenden Zeilen machen den built-in Datentyp Bool bereits zur Instanz der Typklasse Eq: