Ausblick auf den C++14-Standard
Seite 2: Praxis
Neuer Code in alten Compilern
Allerdings ist es schwierig, diesen Unterschied mit einem praktischen Code-Beispiel zu demonstrieren, da in Tests sowohl g++ 4.8.1 als auch Clang++ 3.4 unter Ubuntu 13.10 den im folgenden Listing zu sehenden Code bereits im C++-11-Modus klaglos kompilierten, Clang im C++14-Modus aber mit Fehlermeldungen aus einer Header-Datei ausstieg. g++ hingegen ĂĽbersetzte den Code auch in diesem Modus, ohne zu murren.
std::uniform_real_distribution<double> dDist(0., 5.);
std::mt19937 engine;
auto generator = std::bind(dDist, engine);
std::vector<double> values;
for(std::size_t i=0; i<NVALUES; i++) {
values.push_back(generator());
}
bool ascending = true;
std::sort(
values.begin()
, values.end()
, [=] (double x, double y) /* -> bool*/ {
if(ascending) {
return (x<y);
} else {
return (x>y);
}
}
);
for(const double& d: values) {
std::cout << d << " ";
}
std::cout << std::endl ;
Wer mit C++14 zurzeit produktiv arbeiten möchte, wird vermutlich schnell auf ähnliche Schwierigkeiten stoßen.
Das Listing nutzt zunächst eine der seit C++11 verfügbaren Zufallszahlenverteilungen (gleichverteilte double-Werte zwischen 0 und 5 mit einem Mersenne-Twister-Algorithmus als "Engine"), um einen std::vector mit double-Werten zu füllen. Diese Werte sortiert das Beispiel, wobei es std::sort einen Lambda-Ausdruck übergibt, der abhängig von einer externen Variable entweder auf- oder absteigend sortiert wird. Allerdings ist bei diesem Lambda-Ausdruck der Rückgabetyp auskommentiert mit dem Ziel, ihn vom Compiler automatisch bestimmen zu lassen.
Gemäß Herb Sutters Aussagen vom letzten Jahr sollte es allerdings erst ab C++14 möglich sein, bei einer automatischen Bestimmung des Rückgabewerts mehr als ein return-Statement im Lambda-Ausdruck anzugeben (siehe channel9.msdn.com/Events/Build/2013/2-306, circa Minute 27:30, vgl. auch die zugehörigen Folien, S. 32). In aktuellen Tests funktionierte dies, wie oben erwähnt, allerdings bereits im C++11-Modus von g++ und Clang++.
Die folgende, generische Syntax sollte für die Definition des Lambda-Ausdrucks in C++14 nun ebenfalls möglich sein:
auto lambda = [] (auto x, auto y)
{ return x<y; };
Hier überlässt man es also dem Compiler, neben dem Rückgabe- den Argumenttyp abzuleiten. Allerdings ließ sich das korrekte Funktionieren nicht überprüfen, da sowohl Clang als auch g++ (beide aufgerufen mit --std=c++1y) mit Fehlermeldungen ausstiegen. Dies passierte selbst dann, wenn man den Ausdruck aus dem Paper zu "Generic Lambda Expressions" verwendet:
auto Identity = [](auto a)
{ return a; };
Das LLVM-Projekt führt das Paper explizit zur Erläuterung eines der von Clang 3.4 unterstützten Features auf. Der Autor hat Clang 3.4 aus einem Repository installiert – für alten (C++98- und C++11-) Code funktionierte der Compiler gut. Man sollte hier keine zu strengen Maßstäbe anlegen. C++14 ist noch nicht einmal offiziell veröffentlicht und die Probleme könnten am verwendeten Repository liegen. Allerdings sollte man vor einer ernsthaften Verwendung von C++14 den eingesetzten Compiler hinreichend validieren.
Nicht alle kompilieren alles
Ohne Schwierigkeiten lieĂź sich hingegen die Funktionsdefinition im folgenden Listing verwenden:
auto comp(bool ascending, double x, double y) {
if(ascending) {
return (x<y);
} else {
return (x>y);
}
}
Auch hier war wieder eine Übersetzung mit Clang und g++ im C++11-Modus möglich. Es erschien zwar eine Warnung, die Funktion lieferte gleichwohl die richtigen Ergebnisse. Im Fall von g++ ergab der Aufruf von -- std=c++11 "'comp' function uses 'auto' type specifier without trailing return type". Mit g++ --std=c++1y – also im C++14-Modus – kompilierte der Code ohne Warnung, während clang++ --std=c++1y wie gehabt an einem Problem mit einer Hea der-Datei scheiterte. Übrigens funktioniert das Beispiel aus diesem Listing auch mit Templates:
template <typename T>
auto compT(bool ascending, T x, T y) {
if(ascending) {
return (x<y);
} else {
return (x>y);
}
}
Voraussetzung hierbei ist, dass sich T mittels des <-operator vergleichen lässt.
Eine weitere Neuerung beschreibt ein Papier zum Thema "C++1y/C++14 Support in GCC". C++11 hat das neue Schlüsselwort constexpr eingeführt. Mit seiner Hilfe wurde es möglich, unter bestimmten Bedingungen Funktionen zur Größenangabe eines Arrays bei seiner Deklaration zu verwenden.So kann man seit C++11 schreiben:
constexpr int addr()
{ return 1; }
int myArray[addr() + 4];
Wichtig ist dabei die Zusicherung an den Compiler, dass es sich um eine zur Übersetzungszeit auswertbare Funktion handelt, um den benötigten Speicherplatz zu reservieren. Jedoch gibt es recht weitreichende Restriktionen, was eine mit constexpr markierte Funktion in C++11 enthalten kann. Viele dieser Einschränkungen lockert der geplante C++14-Standard. So sind nun einige Kontrollstrukturen möglich (etwa for- und while-Loops, if und switch). Bisher war lediglich der ?:-Operator erlaubt. Die Regeln für die Verwendung von constexpr sind aber nach wie vor komplex.
Und noch ein Schmankerl: Auch einfache Variablen können in C++14 Templates sein. Das Standardbeispiel ist die Zahl "pi", deren Repräsentation vom verwendeten Typ abhängt (3 für integer, 3.14... mit unterschiedlicher Zahl an Nachkommastellen für float und double). Ein Beispiel aus den "C++ Standards Committee Papers":
template<typename T>
constexpr T pi = —
T(3.1415926535897932385);
Obwohl die Feature-Liste nicht wirklich lang ist, reicht der Platz in diesem Artikel nicht dafür, alle Neuerungen von C++14 im Detail vorzu- stellen. Nicht erwähnt wurden unter anderem "binary literals" (Angabe numerischer Literale in Binärform), decltype(auto) oder das Adressieren eines std::tuple über den Typ, beispielsweise
tuple<string, int> x("hello", 1);
int i = get<int>(x);
Ein guter Ort, um sich ĂĽber alle Features zu informieren, ist die Liste der von Clang 3.4 unterstĂĽtzten C++14-Konstrukte. Hier sind alle notwendigen Dokumente verlinkt. Diese Zusammenstellung der wichtigsten Papers ist ebenfalls informativ, aber deutlich umfangreicher und damit schwerer zu handbaben. Allerdings gibt es in den Dokumenten jeweils kurze Zusammenfassungen.