C++17 im Detail:Vorlagen

C++17 im Detail:Vorlagen

Für C++17 wollte jeder Konzepte haben, und wie Sie wissen, haben wir sie nicht bekommen. Aber bedeutet das, dass C++17 Templates/Templatemeta-Programmierung nicht verbessert? Weit gefehlt! Meiner Meinung nach bekommen wir hervorragende Features.

Lesen Sie mehr für Details.

Einführung

Arbeiten Sie viel mit Templates und Metaprogrammierung?
Mit C++17 bekommen wir ein paar nette Verbesserungen:Einige sind ziemlich klein, aber es gibt auch bemerkenswerte Funktionen! Alles in allem sollten die Ergänzungen das Schreiben von Vorlagencode erheblich verbessern.

Heute habe ich darüber geschrieben:

  • Ableitung von Vorlagenargumenten für Klassenvorlagen
  • template<auto>
  • Ausdrücke falten
  • constexpr if
  • Plus einige kleinere, detaillierte Verbesserungen/Korrekturen

Übrigens:Wenn Sie wirklich mutig sind, können Sie immer noch Konzepte verwenden! Sie werden in GCC zusammengeführt, sodass Sie damit spielen können, noch bevor sie endgültig veröffentlicht werden.

Die Serie

Dieser Beitrag ist der dritte in der Reihe über C++17-Funktionsdetails.

Der Plan für die Serie

  1. Korrekturen und Einstellung
  2. Sprachklärung
  3. Vorlagen (heute )
  4. Attribute
  5. Vereinfachung
  6. Bibliothek ändert -Dateisystem
  7. Bibliotheksänderungen - ParallelAlgorithms
  8. Bibliotheksänderungen -Utils
  9. Abschluss, Bonus – mit einem kostenlosen E-Book! :)

Nur zur Erinnerung:

Wenn Sie sich zunächst selbst mit dem Standard befassen möchten, können Sie den neuesten Entwurf hier lesen:

N4659, 2017-03-21, Arbeitsentwurf, Standard für die Programmiersprache C++

  • der Link erscheint auch auf isocpp.org.

WG21 P0636r0:Änderungen zwischen C++14 und C++17

Compilerunterstützung:C++-Compilerunterstützung

Außerdem habe ich eine Liste mit kurzen Beschreibungen aller Sprachfunktionen von C++17 vorbereitet:

Laden Sie eine kostenlose Kopie meines C++17 CheatSheets herunter!

Es ist eine einseitige Referenzkarte, PDF.

Es gibt auch einen Vortrag von Bryce Lelbach:C++Now 2017:C++17Features

Und werfen Sie einen Blick auf meinen Beitrag zu den C++17-Master-Features:C++17Features

Ableitung von Vorlagenargumenten für Klassenvorlagen

Ich habe gute und schlechte Nachrichten für dich :)

Verwenden Sie oft make<T> Funktionen zum Erstellen eines Vorlagenobjekts (wie std::make_pair )?
Mit C ++ 17 können Sie (die meisten) davon vergessen und einfach einen regulären Konstruktor verwenden :)
Das bedeutet auch, dass ein Großteil Ihres Codes - diese make<T> Funktionen können jetzt entfernt werden.

Der Grund?

C++17 füllte eine Lücke in den Abzugsregeln für Templates. Jetzt kann die Template-Ableitung für Standard-Klassen-Templates und nicht nur für Funktionen erfolgen.

Beispielsweise ist (und war) der folgende Code legal:

void f(std::pair<int, char>);

// call:
f(std::make_pair(42, 'z'));

Weil std::make_pair ist eine Vorlagenfunktion (damit wir eine Vorlagenableitung durchführen können).

Aber das Folgende war nicht (vor C++17)

void f(std::pair<int, char>);

// call:
f(std::pair(42, 'z'));

Sieht genauso aus, oder? Dies war nicht in Ordnung, weil std::pair ist eine Vorlagenklasse, und Vorlagenklassen konnten bei ihrer Initialisierung keine Typableitung anwenden.

Aber jetzt können wir das tun, damit der obige Code unter einem C++17-konformen Compiler kompiliert wird.

Was ist mit dem Erstellen lokaler Variablen wie Tupel oder Paare?

std::pair<int, double> p(10, 0.0);
// same as
std::pair p(10, 0.0); // deduced automatically!

Versuchen Sie es im Compiler Explorer:Beispiel GCC7.1.

Dadurch können komplexe Konstruktionen wie

erheblich reduziert werden
std::lock_guard<std::shared_timed_mutex, 
        std::shared_lock<std::shared_timed_mutex>> lck(mut_, r1);

Kann jetzt werden:

std::lock_guard lck(mut_, r1);

Beachten Sie, dass ein teilweiser Abzug nicht stattfinden kann, Sie müssen alle Template-Parameter angeben oder keine:

std::tuple t(1, 2, 3);              // OK: deduction
std::tuple<int,int,int> t(1, 2, 3); // OK: all arguments are provided
std::tuple<int> t(1, 2, 3);         // Error: partial deduction

Wenn Sie abenteuerlustig sind, können Sie auch Ihre benutzerdefinierten Klassen-Template-Deduction-Guides erstellen:Weitere Informationen finden Sie hier:Letzter Beitrag:ArneMertz:Modern C++ Features - Class Template ArgumentDeduction.

Übrigens:warum nicht alle make Funktionen können entfernt werden? Betrachten Sie beispielsweise make_unique oder make_shared Sind sie nur für „syntaktischen Zucker“? Oder haben sie andere wichtige Anwendungen? Ich lasse das als Übung :)

Weitere Details in

  • P0091R3
  • Simon Brand:Ableitung von Template-Argumenten für Klassen-Template-Konstruktoren
  • Ableitung von Klassenvorlagen (seit C++17) -cpreference.

MSVC noch nicht , GCC:7.0, Clang:noch nicht .

Vorlagenparameter ohne Typ mit auto deklarieren

Dies ist ein weiterer Teil der Strategie, auto zu verwenden überall, überallhin, allerorts. Mit C++11 und C++14 können Sie damit Variablen oder sogar Rückgabetypen automatisch ableiten, außerdem gibt es auch generische Lambdas. Jetzt können Sie es auch zum Ableiten von Nicht-Typ-Template-Parametern verwenden.

Zum Beispiel:

template <auto value> void f() { }

f<10>();               // deduces int

Dies ist nützlich, da Sie keinen separaten Parameter für den Typ des Nicht-Typ-Parameters haben müssen. Wie:

template <typename Type, Type value> constexpr Type TConstant = value;
                // ^^^^                        ^^^^  
constexpr auto const MySuperConst = TConstant<int, 100>;

mit C++17 ist es etwas einfacher:

template <auto value> constexpr auto TConstant = value;
                             // ^^^^
constexpr auto const MySuperConst = TConstant <100>;

Es ist also nicht nötig, Type zu schreiben explizit.

Als eine der fortgeschrittenen Verwendungen verweisen viele Artikel/Blogs/Vorträge auf ein Beispiel einer heterogenen Kompilierzeitliste:

template <auto ... vs> struct HeterogenousValueList {};
using MyList = HeterogenousValueList<'a', 100, 'b'>;

Vor C++17 war es nicht möglich, eine solche Liste direkt zu deklarieren, es musste zuerst eine Wrapper-Klasse bereitgestellt werden.

Weitere Details in

  • P0127R2 – Deklarieren von Nicht-Typ-Vorlagenparametern mit auto
  • P0127R1 – Deklarieren von Nicht-Typ-Template-Argumenten mit automatischer Motivation, Beispiele, Diskussion.
  • c++ – Vorteile von auto in Template-Parametern in C++17 – StackOverflow
  • Reisebericht:Sommertreffen der ISO C++ Standards (Oulu) | SuttersMühle

MSVC noch nicht , GCC:7.0, Clang:4.0.

Fold-Ausdrücke

Mit C++11 haben wir variadische Templates bekommen, was ein großartiges Feature ist, besonders wenn Sie mit einer variablen Anzahl von Eingabeparametern für eine Funktion arbeiten möchten. Früher (vor C++11) mussten Sie zum Beispiel mehrere verschiedene Versionen einer Funktion schreiben (wie eine für einen Parameter, eine andere für zwei Parameter, eine andere für drei Parameter …).

Dennoch erforderten unterschiedliche Vorlagen etwas zusätzlichen Code, wenn Sie „rekursive“ Funktionen wie sum implementieren wollten , all . Sie mussten Regeln für die Rekursion angeben:

Zum Beispiel:

auto SumCpp11(){
    return 0;
}

template<typename T1, typename... T>
auto SumCpp11(T1 s, T... ts){
    return s + SumCpp11(ts...);
}

Und mit C++17 können wir viel einfacheren Code schreiben:

template<typename ...Args> auto sum(Args ...args) 
{ 
    return (args + ... + 0); 
}

// or even:

template<typename ...Args> auto sum2(Args ...args) 
{ 
    return (args + ...);
}

Falten Sie Ausdrücke über ein Parameterpaket.

Ebenfalls standardmäßig erhalten wir die folgenden Werte für leere Parameterpakete (P0036R0):

Hier ist eine recht nette Implementierung eines printf Falten verwenden:

template<typename ...Args>
void FoldPrint(Args&&... args) {
    (cout << ... << forward<Args>(args)) << '\n';
}

Oder ein Komma-Operator umklappen:

template<typename T, typename... Args>
void push_back_vec(std::vector<T>& v, Args&&... args)
{
    (v.push_back(args), ...);
}

Im Allgemeinen ermöglicht der Fold-Ausdruck das Schreiben von saubererem, kürzerem und wahrscheinlich leichter zu lesendem Code.

Näheres unter:

  • N4295 und P0036R0
  • „Fold-Ausdrücke verwenden, um variadische Funktionsvorlagen zu vereinfachen“ in Modern C++ Programming Cookbook.
  • Simon Brand:Explodierende Tupel mit Foldexpressions
  • Baptiste Wicht:C++17 FoldExpressions
  • Fold-Ausdrücke -ModernesCpp.com

MSVC noch nicht , GCC:6.0, Clang:3.6 (N4295)/3.9(P0036R0).

constexpr if

Das ist eine große Sache!

Das statische if für C++!

Mit dieser Funktion können Sie Verzweigungen einer if-Anweisung zur Kompilierzeit basierend auf einer konstanten Ausdrucksbedingung verwerfen.

if constexpr(cond)
     statement1; // Discarded if cond is false
else
     statement2; // Discarded if cond is true

Zum Beispiel:

template <typename T>
auto get_value(T t) {
    if constexpr (std::is_pointer_v<T>)
        return *t;
    else
        return t;
}

Dadurch entfällt ein Großteil der Notwendigkeit für das Tag-Dispatching und SFINAE und sogar für #ifdefs .

Ich möchte auf dieses Feature zurückkommen, wenn wir über Features von C++17 sprechen, die die Sprache vereinfachen. Ich hoffe, mit weiteren Beispielen für constexpr if zurückzukommen .

Näheres unter:

  • P0292R2
  • Simon Brand:Vereinfachung von Vorlagen und #ifdefs mit ifconstexpr

MSVC 2017, GCC:7.0, Clang:3.9.

Andere

In C++17 gibt es auch andere Sprachfeatures im Zusammenhang mit Templates. In diesem Beitrag wollte ich mich auf die größten Verbesserungen konzentrieren, also erwähne ich die anderen nur kurz:

  • typename zulassen in einer Vorlage Vorlagenparameter:N4051.

    • Erlaubt Ihnen die Verwendung von typename statt class beim Deklarieren eines Vorlagenparameters. Normale Typparameter können sie austauschbar verwenden, aber Template-Template-Parameter wurden auf class beschränkt .
  • DR:Matching von Template-Template-Argumenten schließt kompatible Templates aus:P0522R0.

    • Verbessert den Abgleich von Template-Argumenten. Behebt Kernproblem CWG150.
  • Konstante Auswertung für alle Nicht-Typ-Template-Argumente zulassen:N4268

    • Entfernen Sie syntaktische Beschränkungen für Zeiger, Verweise und Verweise auf Mitglieder, die als Nicht-Typ-Vorlagenparameter erscheinen:
  • constexpr Lambdas:P0170R1

    • Lambda-Ausdrücke können jetzt konstante Ausdrücke sein.

Zusammenfassung

Verbessert C++17 Templates und Metaprogrammierung? Definitiv!

Wir haben wirklich solide Funktionen wie die Vorlagenableitung für Klassenvorlagen, template<auto> plus einige detaillierte Funktionen, die einige der Probleme beheben.

Dennoch ist für mich constexpr if die mächtigste Funktion, die einen erheblichen Einfluss auf den Code haben könnte und Falten. Sie bereinigen den Code erheblich und machen ihn lesbarer.

Was sind Ihre Lieblingsteile in Bezug auf Vorlagen?

Beim nächsten Mal werden wir Attribute wie [[fallthrough]] ansprechen oder[[nodiscard]] , und ich möchte an andere, bereits vorhandene Attribute erinnern. Bleiben Sie dran!

Denken Sie noch einmal daran, sich meine C++17 Language RefCard zu schnappen .