C++17 – Was gibt’s Neues? Ein Überblick über die wichtigsten Erweiterungen

Autor / Redakteur: Rainer Grimm * / Sebastian Gerstl |

Ende 2017 wurde es vollbracht: C++17 ist als neuer ISO-Standard einstimmig verabschiedet. Da stellt sich natürlich die Frage, was gibt es denn an konkreten Neuerungen in C++17? Und wir wirkt sich das für Softwareentwickler aus?

Bild 1: Der Zeitstrahl demonstriert, wie sowohl die C++-Kernsprache als auch die C++-Standardbibliothek deutlich mächtiger geworden sind.
Bild 1: Der Zeitstrahl demonstriert, wie sowohl die C++-Kernsprache als auch die C++-Standardbibliothek deutlich mächtiger geworden sind.
(Bild: Rainer Grimm)

Bevor der hier vorliegende Artikel nun den Blick auf die Details zu C++17 schärft, ist es zuerst notwendig, das große Bild im Auge zu behalten. C++17 setzt die Serie von neuen C++-Standards im Drei-Jahres-Rhythmus konsequent um (siehe Bild 1). Der Zeitstrahl zeigt bereits: Sowohl die C++-Kernsprache als auch die C++-Standardbibliothek sind deutlich mächtiger geworden.

Bildergalerie
Bildergalerie mit 5 Bildern

Die verbesserte Kernsprache

Fold expressions, constexpr if, Initialisierer in if und switch Anweisungen, structured binding Deklarationen, automatische Typbestimmung für Konstruktoren von Templates, Vermeindung von Kopieren; die Liste an neuen Features in C++ ist lang. Sowohl für den Anwender als auch für den Bibliotheksautoren in C++ sind viele Perlen dabei.

Fold Expressions

C++11 unterstützt Variadic Templates. Dies sind Templates, die eine beliebige Anzahl an Argumenten annehmen können. Die beliebige Anzahl wird von einem Parameter-Pack gehalten.

Neu ist mit C++17, dass dieses Parameter-Pack direkt mit einem binären Operator zur Übersetzungszeit reduziert werden kann.

#include <iostream>

template<typename... Args>
bool all(Args... args) { return (... && args); }

int main(){

    std::cout << std::boolalpha;
    std::cout << "all(): " << all() << std::endl;
    std::cout << "all(true): " << all(true) << std::endl;
    std::cout << "all(true, true, true, false): " << all(true, true, true, false) << std::endl;

    std::cout << std::endl;

}

Der binäre Operator des Funktions-Templates all ist das logische UND (&&). Hier ist die Ausgabe des Programms:

Output:

all(): true
all(true): true
all(true, true, true, false): false

Es geht mit den Features zur Übersetzungszeit weiter.

Constexpr if

constexpr if erlaubt es, Sourcecode bedingt zu übersetzten.

template <typename T>
auto get_value(T t){
     if constexpr (std::is_pointer_v)    //(1)
        return *t; // deduces return type to int for T = int*
    else     //(2)
return t;    // deduces return type to int for T = int
}

Falls T ein Zeiger ist, dann wird der if Zweig (1) der Funktion get_value übersetzt, falls nicht, der else Zweig (2). Zwei Punkte sind in diesem Zusammenhang wichtig. Die Funktion get_value besitzt zwei verschiedene Rückgabetypen und beide Zweige der if-Anweisungen müssen gültig sein.

Konsequenterweise können if und switch Anweisungen in C++17 das, was for Anweisungen schon lange konnten.

Initialisierer in 'if' und 'switch' Anweisungen

Variablen können in C++17 direkt in if und switch Anweisungen initialisiert werden.

std::map<int,std::string> myMap;

if (auto result = myMap.insert(value); result.second){
/     useResult(result.first);
    // ...
}
else{
    //...
} // result is automatically destroyed

Die Variable result ist nur innerhalb des if und else Zweigs der if-Anweisung gültig. result verschmutzt daher nicht den umgebenden Bereich.

Falls der Initialisierer in if und switch Anweisungen zusammen mit der structured binding Deklaration zum Einsatz kommt, wird die C++ Syntax noch eleganter.

Structurted binding Deklarationen

Dank structured binding lässt sich direkt ein std::tuple oder ein struct an eine Variable binden. Damit wird das vorherige Beispiel deutlich lesbarer.

std::map<int,std::string> myMap;

if (auto [iter, succeeded] = myMap.insert(value); succeeded) {// (1)
    useIter(iter);
    // ...
}
else{
    //...
} //iter and succeded are automatically be destroyed

auto [iter, succeeded] (1) erzeugt automatisch die zwei Variablen iter und succeeded. In der letzten Zeile werden sie wieder gelöscht.

Das ist ein Feature in C++17, mit dem Programmieren leichter von der Hand wird. Das gleiche gilt für die automatische Template-Typ Ableitung von Konstruktoren.

(ID:45095872)