C++14 - C++14

C++14 ist eine Version des ISO / IEC 14882-Standards für die Programmiersprache C++ . Es soll eine kleine Erweiterung gegenüber C++11 sein , die hauptsächlich Fehlerbehebungen und kleine Verbesserungen enthält. Die Zulassung wurde am 18. August 2014 bekannt gegeben. C++14 wurde im Dezember 2014 als ISO/IEC 14882:2014 veröffentlicht.

Da frühere Überarbeitungen des C++-Standards merklich verspätet waren, wurde stattdessen bis zu seiner Freigabe manchmal der Name "C++1y" verwendet, ähnlich wie der C++11-Standard in Erwartung seiner Veröffentlichung "C++0x" genannt wurde vor 2010 (obwohl es in 2010 und schließlich 2011 abgerutscht ist).

Neue Sprachfunktionen

Dies sind die Funktionen, die der Kernsprache von C++14 hinzugefügt wurden.

Abzug des Funktionsrückgabetyps

C++11 ermöglichte es Lambda-Funktionen , den Rückgabetyp basierend auf dem Typ des Ausdrucks abzuleiten, der der Rückgabeanweisung übergeben wurde. C++14 bietet diese Fähigkeit für alle Funktionen. Es erweitert diese Möglichkeiten auch auf Lambda-Funktionen und ermöglicht die Ableitung des Rückgabetyps für Funktionen, die nicht der Form entsprechen return expression;.

Um die Ableitung des Rückgabetyps zu induzieren, muss die Funktion mit autoals Rückgabetyp deklariert werden , jedoch ohne den nachfolgenden Rückgabetypspezifizierer in C++11:

auto DeduceReturnType();   // Return type to be determined.

Wenn in der Implementierung der Funktion mehrere Rückgabeausdrücke verwendet werden, müssen sie alle denselben Typ ableiten.

Funktionen, die ihre Rückgabetypen ableiten, können vorwärts deklariert werden, aber sie können nicht verwendet werden, bis sie definiert wurden. Ihre Definitionen müssen der Übersetzungseinheit zur Verfügung stehen, die sie verwendet.

Rekursion kann mit einer Funktion dieses Typs verwendet werden, aber der rekursive Aufruf muss nach mindestens einer return-Anweisung in der Definition der Funktion erfolgen:

auto Correct(int i)
{
  if (i == 1)
    return i;             // return type deduced as int

  return Correct(i-1)+i;  // ok to call it now
}

auto Wrong(int i)
{
  if (i != 1)
    return Wrong(i-1)+i;  // Too soon to call this. No prior return statement.

  return i;               // return type deduced as int
}

Abweichender Typabzug bei Deklaration

In C++11 wurden zwei Methoden der Typableitung hinzugefügt. autowar eine Möglichkeit, basierend auf einem bestimmten Ausdruck eine Variable des entsprechenden Typs zu erstellen. decltypewar eine Möglichkeit, den Typ eines bestimmten Ausdrucks zu berechnen. Jedoch, decltypeund autoTypen auf unterschiedliche Weise herleiten. autoDeduziert insbesondere immer einen Nicht-Referenztyp, als ob mit verwendet würde std::decay, während auto&&immer ein Referenztyp abgeleitet wird. Jedoch decltypekann prodded in einen Referenz- oder Nicht-Referenztyp herzuleiten, basierend auf dem Wert der Kategorie des Ausdrucks und der Art des Ausdrucks wird herzuleiten:

int   i;
int&& f();
auto          x3a = i;     // decltype(x3a) is int
decltype(i)   x3d = i;     // decltype(x3d) is int
auto          x4a = (i);   // decltype(x4a) is int
decltype((i)) x4d = (i);   // decltype(x4d) is int&
auto          x5a = f();   // decltype(x5a) is int
decltype(f()) x5d = f();   // decltype(x5d) is int&&

C++14 fügt die decltype(auto)Syntax hinzu. Dadurch können autoDeklarationen die decltypeRegeln für den angegebenen Ausdruck verwenden.

Die decltype(auto)Syntax kann auch mit Rückgabetypableitung verwendet werden , indem decltype(auto)Syntax anstelle der autoRückgabetypableitung der Funktion verwendet wird.

Lockere Constexpr-Einschränkungen

C++11 führte das Konzept einer von constexpr deklarierten Funktion ein; eine Funktion, die zur Kompilierzeit ausgeführt werden könnte. Ihre Rückgabewerte könnten von Operationen verwendet werden, die konstante Ausdrücke erfordern, wie z. B. ein ganzzahliges Vorlagenargument. C++11-constexpr-Funktionen können jedoch nur einen einzelnen zurückgegebenen Ausdruck enthalten (sowie static_asserts und eine kleine Anzahl anderer Deklarationen).

C++14 lockert diese Einschränkungen. Von Constexpr deklarierte Funktionen können jetzt Folgendes enthalten:

  • Alle Erklärungen außer:
    • staticoder thread_localVariablen.
    • Variablendeklarationen ohne Initialisierer.
  • Die bedingten Verzweigungsanweisungen ifund switch.
  • Jede Schleifenanweisung, einschließlich bereichsbasierter for.
  • Ausdrücke, die den Wert eines Objekts ändern, wenn die Lebensdauer dieses Objekts innerhalb der konstanten Ausdrucksfunktion begann. Dies schließt Aufrufe aller nicht const constexprdeklarierten nicht-statischen Memberfunktionen ein.

goto -Anweisungen sind in C++14-entspannten constexpr-deklarierten Funktionen verboten.

Außerdem gab C++11 an, dass alle deklarierten nicht-statischen Memberfunktionen constexprauch implizit constin Bezug auf deklariert wurden this. Das wurde inzwischen entfernt; nicht statische Memberfunktionen können nicht- sein const. Gemäß den obigen Einschränkungen kann eine Nicht- const constexprMember-Funktion jedoch einen Klassenmember nur ändern, wenn die Lebensdauer dieses Objekts innerhalb der konstanten Ausdrucksauswertung begann.

Variable Vorlagen

In früheren Versionen von C++ konnten nur Funktionen, Klassen oder Typaliase erstellt werden. C++14 ermöglicht die Erstellung von Variablen, die auf Vorlagen basieren. Ein Beispiel , bei dem Vorschlag gegeben ist eine Variable , pidie gelesen werden können , den Wert zu erhalten pi für verschiedene Arten (beispielsweise 3wenn es als integralen Typen lesen, der am nächsten Wert möglich float, doubleoder long doublePräzision beim Lesen wie float, doubleoder long doubleist; usw. ).

Für solche Erklärungen und Definitionen gelten die üblichen Musterregeln, einschließlich der Spezialisierung.

template<typename T>
constexpr T pi = T(3.141592653589793238462643383);

// Usual specialization rules apply:
template<>
constexpr const char* pi<const char*> = "pi";

Initialisierung von Aggregatmitgliedern

C++11 fügte Memberinitialisierer hinzu, Ausdrücke, die auf Member im Klassenbereich angewendet werden, wenn ein Konstruktor den Member selbst nicht initialisiert hat. Die Definition von Aggregaten wurde geändert, um alle Klassen mit Memberinitialisierern explizit auszuschließen; Daher dürfen sie die Aggregatinitialisierung nicht verwenden.

C++14 lockert diese Einschränkung und ermöglicht die Aggregatinitialisierung für solche Typen. Wenn die Init-Liste mit Klammern keinen Wert für dieses Argument bereitstellt, kümmert sich der Member-Initialisierer darum.

Binäre Literale

Numerische Literale in C++14 können in binärer Form angegeben werden . Die Syntax verwendet die Präfixe 0boder 0B. Die Syntax wird auch in anderen Sprachen wie Java , C# , Swift , Go , Scala , Ruby , Python , OCaml und als inoffizielle Erweiterung in einigen C-Compilern seit mindestens 2007 verwendet.

Zifferntrenner

In C ++ 14 kann die einzelne Anführungszeichen willkürlich als A verwendet werden digit Separators in Zahlenliterale, beide Integer - Literale und Gleitkomma Literale. Dies kann es menschlichen Lesern erleichtern, große Zahlen durch Subitisierung zu analysieren .

auto integer_literal = 1'000'000;
auto floating_point_literal = 0.000'015'3;
auto binary_literal = 0b0100'1100'0110;
auto a_dozen_crores = 12'00'00'000;

Generische Lambdas

In C++11 müssen Lambda-Funktionsparameter mit konkreten Typen deklariert werden. C++14 lockert diese Anforderung, sodass Lambda-Funktionsparameter mit dem autoTypspezifizierer deklariert werden können.

auto lambda = [](auto x, auto y) {return x + y;};

Was die autoTypableitung betrifft, folgen generische Lambdas den Regeln der Vorlagenargumentableitung (die ähnlich, aber nicht in jeder Hinsicht identisch sind). Der obige Code entspricht diesem:

struct
{
  template<typename T, typename U>
    auto operator()(T x, U y) const {return x + y;}
} lambda{};

Generische Lambdas sind im Wesentlichen templatgesteuerte Funktor-Lambdas.

Lambda-Capture-Ausdrücke

C++11-Lambda-Funktionen erfassen Variablen, die in ihrem äußeren Gültigkeitsbereich durch Wertkopie oder Referenz deklariert wurden. Das bedeutet, dass Wertmember eines Lambda keine reinen Move-Typen sein können. C++14 ermöglicht die Initialisierung von erfassten Membern mit beliebigen Ausdrücken. Dies ermöglicht sowohl das Erfassen durch value-move als auch das Deklarieren beliebiger Member des Lambda, ohne dass eine entsprechend benannte Variable in einem äußeren Gültigkeitsbereich vorhanden ist.

Dies geschieht über die Verwendung eines Initialisierungsausdrucks:

auto lambda = [value = 1] {return value;};

Die Lambda-Funktion lambdagibt 1 zurück, womit sie valueinitialisiert wurde. Die deklarierte Erfassung leitet den Typ aus dem Initialisierungsausdruck ab, als ob von auto.

Dies kann verwendet werden, um durch die Verwendung der Standardfunktion zu erfassen std::move:

std::unique_ptr<int> ptr(new int(10));
auto lambda = [value = std::move(ptr)] {return *value;};

Das Attribut [[deprecated]]

Das deprecatedAttribut ermöglicht das Markieren einer Entität als veraltet , wodurch die Verwendung weiterhin zulässig ist, Benutzer jedoch darauf hingewiesen werden, dass von der Verwendung abgeraten wird und während der Kompilierung eine Warnmeldung ausgegeben werden kann. Ein optionales Zeichenfolgenliteral kann als Argument von deprecatederscheinen, um die Gründe für die Einstellung zu erläutern und eine Ersetzung vorzuschlagen.

[[deprecated]] int f();

[[deprecated("g() is thread-unsafe. Use h() instead")]]
void g( int& x );

void h( int& x );

void test()
{
  int a = f(); // warning: 'f' is deprecated
  g(a); // warning: 'g' is deprecated: g() is thread-unsafe. Use h() instead
}

Neue Standardbibliotheksfunktionen

Gemeinsame Mutexe und Sperren

C++14 fügt einen gemeinsam genutzten zeitgesteuerten Mutex und einen begleitenden gemeinsam genutzten Sperrtyp hinzu.

Heterogene Suche in assoziativen Containern

Die C++-Standardbibliothek definiert vier assoziative Containerklassen. Diese Klassen ermöglichen es dem Benutzer, einen Wert basierend auf einem Wert dieses Typs nachzuschlagen. Die Map-Container ermöglichen es dem Benutzer, einen Schlüssel und einen Wert anzugeben, wobei die Suche nach Schlüssel erfolgt und einen Wert zurückgibt. Die Suche erfolgt jedoch immer nach dem spezifischen Schlüsseltyp, sei es der Schlüssel wie in Maps oder der Wert selbst wie in Sets.

C++14 erlaubt die Suche über einen beliebigen Typ, solange der Vergleichsoperator diesen Typ mit dem tatsächlichen Schlüsseltyp vergleichen kann. Dies würde es einer Zuordnung von std::stringbis zu einem Wert ermöglichen, mit einem const char*oder einem anderen Typ zu vergleichen, für den eine operator< Überladung verfügbar ist. Es ist auch nützlich, um zusammengesetzte Objekte in a std::setnach dem Wert eines einzelnen Elements zu indizieren, ohne den Benutzer von findzu zwingen , ein Dummy-Objekt zu erstellen (z. B. ein Ganzes zu erstellen struct Person, um eine Person anhand des Namens zu finden).

Um die Abwärtskompatibilität zu wahren, ist heterogenes Nachschlagen nur zulässig, wenn der dem assoziativen Container übergebene Komparator dies zulässt. Die Standardbibliotheksklassen std::less<>und std::greater<>werden erweitert, um eine heterogene Suche zu ermöglichen.

Benutzerdefinierte Standardliterale

C++11 definierte die Syntax für benutzerdefinierte Literal-Suffixe, aber die Standardbibliothek verwendete keines davon. C++14 fügt die folgenden Standardliterale hinzu:

  • "s", um die verschiedenen std::basic_stringTypen zu erstellen .
  • "h", "min", "s", "ms", "us", "ns", um die entsprechenden std::chrono::durationZeitintervalle zu erstellen .
  • "if", "i", "il", für die entsprechende Erstellung std::complex<float>, std::complex<double>und std::complex<long double>imaginäre Zahlen.
auto str = "hello world"s; // auto deduces string
auto dur = 60s;            // auto deduces chrono::seconds
auto z   = 1i;             // auto deduces complex<double>

Die beiden "s"-Literale interagieren nicht, da der String one nur mit String-Literalen arbeitet und der für Sekunden nur mit Zahlen.

Tupeladressierung über Typ

Der std::tuplein C++11 eingeführte Typ ermöglicht die Indizierung eines Aggregats typisierter Werte durch eine konstante Ganzzahl zur Kompilierzeit. C++14 erweitert dies, um das Abrufen aus einem Tupel nach Typ statt nach Index zu ermöglichen. Wenn das Tupel mehr als ein Element des Typs enthält, führt dies zu einem Kompilierzeitfehler:

tuple<string, string, int> t("foo", "bar", 7);
int i = get<int>(t);        // i == 7
int j = get<2>(t);          // Same as before: j == 7
string s = get<string>(t);  // Compile-time error due to ambiguity

Kleinere Bibliotheksfunktionen

std::make_uniquekann wie std::make_sharedfür std::unique_ptrObjekte verwendet werden.

std::integral_constanteine operator()Überladung erhalten, um den konstanten Wert zurückzugeben.

Die Klassenvorlage std::integer_sequenceund zugehörige Aliasvorlagen wurden hinzugefügt, um Ganzzahlsequenzen zur Kompilierzeit darzustellen, wie z. B. die Indizes von Elementen in einem Parameterpaket.

Die globalen std::begin/ std::end-Funktionen wurden um std::cbegin/ std::cend-Funktionen erweitert, die konstante Iteratoren zurückgeben, und std::rbegin/ std::rendund std::crbegin/, std::crenddie umgekehrte Iteratoren zurückgeben.

Die std::exchangeFunktionsvorlage weist einer Variablen einen neuen Wert zu und gibt den alten Wert zurück.

Neue Überladungen von std::equal, std::mismatch, und std::is_permutationnehmen ein Paar Iteratoren für den zweiten Bereich, damit der Aufrufer nicht separat prüfen muss, ob die beiden Bereiche die gleiche Länge haben.

Das std::is_finalTypmerkmal erkennt, ob eine Klasse markiert ist final.

Der std::quotedStream-I/O-Manipulator ermöglicht das Einfügen und Extrahieren von Zeichenfolgen mit eingebetteten Leerzeichen, indem Begrenzer (standardmäßig doppelte Anführungszeichen) bei der Ausgabe platziert und bei der Eingabe entfernt und alle eingebetteten Trennzeichen mit Escape-Zeichen versehen werden.

Compiler-Unterstützung

Clang beendete die Unterstützung für C++14 in 3.4, allerdings unter dem Standardnamen c++1y, und machte C++14 zum Standard-C++-Standard in Clang 6. GCC beendete die Unterstützung für C++14 in GCC 5 und machte C+ +14 der Standard-C++-Standard in GCC 6. Microsoft Visual Studio 2017 hat "fast alle" C++14-Funktionen implementiert.

Verweise

Externe Links