Beim letzten Mal haben wir SFINAE verwendet, um herauszufinden, ob ein Typ eine Definition hat, und wir haben sie in Kombination mit
if constexpr
und generischen Lambda-Ausdrücken verwendet, damit der Code den Typ verwenden kann, wenn er definiert ist, während er vom Compiler weiterhin akzeptiert wird (und verworfen), wenn der Typ nicht definiert ist.
Bei dieser Anwendung gibt es jedoch mehrere Probleme:
- Jedes Mal, wenn Sie eine
struct
schreiben müssen. - Wenn der Typ nicht vorhanden ist, wird dieser Typ beim Benennen im aktuellen Namespace und nicht in dem Namespace eingegeben, in dem der Typ sein soll.
- Sie müssen eine
struct
mit einem nicht qualifizierten Namen verwenden. Sie können damit nicht nach einem Typ suchen, den Sie nicht in den aktuellen Namespace importiert haben.
Wir können alle drei Probleme mit einer Lösung beheben: Deklarieren Sie zuerst den Typ im gewünschten Namespace.

Nachdem Sie dies getan haben, müssen Sie keine Struktur schreiben, da die Struktur deklariert wurde. Die Verwendung als Vorlagentypparameter in
call_if_defined
führt nicht zur Erstellung einer neuen Deklaration, da bereits alles deklariert wurde. Und da sie deklariert wurde, können Sie über ihren unqualifizierten Namen, ihren vollständigen Namespace-Namen oder über alles dazwischen auf sie zugreifen. Auch über einen Typalias oder einen abhängigen Typ (leider liegen sie nicht dazwischen).
namespace app { void foo() { call_if_defined<awesome::special>([&](auto* p) {
Diejenigen, die diese Artikelserie von Anfang an verfolgt haben, haben möglicherweise bemerkt, dass die Methode
call_if_defined
nicht genau mit der Version übereinstimmt, die wir zuvor geschrieben haben. Die neue Version unterstützt mehrere Typparameter und ruft nur dann ein Lambda auf, wenn alle Typen definiert sind.
Schauen wir uns das genauer an:
template<typename... T, typename TLambda> void call_if_defined(TLambda&& lambda) { if constexpr ((... && is_complete_type_v<T>)) { lambda(static_cast<T*>(nullptr)...); } }
Die doppelten Klammern in if constexpr ((...)) sehen seltsam aus, sind aber erforderlich. Externe Klammern werden von der
if constexpr
, und interne Klammern werden
von einem Faltungsausdruck benötigt. Der Faltungsausdruck erweitert sich zu
if constexpr ( (is_complete_type_v<T1> && is_complete_type_v<T2> && ... is_complete_type_v<Tn>))
Der Lambda-Aufruf verwendet die
Parameterpaket-Erweiterung :
lambda(static_cast<T*>(nullptr)...);
Es erweitert sich zu
lambda(static_cast<T1*>(nullptr), static_cast<T2*>(nullptr), ..., static_cast<Tn*>(nullptr));
Dabei wird
static_cast<T*>(nullptr)
für jeden Typ einmal wiederholt.
Wie bereits erwähnt, können wir diese Funktion verwenden, um das Lambda aufzurufen, wenn alle Typen definiert sind:
void foo(Source const& source) { call_if_defined<special, magic>( [&](auto* p1, auto* p2) { using special = std::decay_t<decltype(*p1)>; using magic = std::decay_t<decltype(*p2)>; auto s = source.try_get<special>(); if (s) magic::add_magic(s); }); }
Mit C ++ 20 können Sie es folgendermaßen schreiben:
void foo(Source const& source) { call_if_defined<special, magic>( [&]<typename special, typename magic> (special*, magic*) { auto s = source.try_get<special>(); if (s) magic::add_magic(s); }); }
Auf diese Weise können Sie den Typ der Vorlage benennen, sodass Sie sie beim Spielen mit
std::decay_t
erneut extrahieren
std::decay_t
.
Im nächsten Artikel werden wir dies als Sprungbrett verwenden und die Schaltung erweitern.
Hinweis : Dies ist der vierte Teil der Hauptartikelserie, es gibt jedoch noch andere Teile (
1 ,
2 ,
3 ,
5 ). Für Ungeduldige: Folgendes müssen Sie kopieren und einfügen:
template<typename, typename = void> constexpr bool is_type_complete_v = false; template<typename T> constexpr bool is_type_complete_v <T, std::void_t<decltype(sizeof(T))>> = true; template<typename... T, typename TLambda> void call_if_defined(TLambda&& lambda) { if constexpr ((... && is_complete_type_v<T>)) { lambda(static_cast<T*>(nullptr)...); } }
Übrigens haben wir einen coolen Job
Seit mehr als einem Jahrzehnt ist
Havok führend bei Innovationen in der Spieleentwicklung und im interaktiven 3D. Als Teil von Cognition, dem HoloLens-Team, kombinieren wir jetzt dieses Know-how und die Leistungsfähigkeit der Azure-Cloud, um viele aufregende neue Mixed-Reality-Dienste zu entwickeln. Darunter befindet sich der kürzlich angekündigte Azure Remote Rendering-Dienst. Wir kombinieren leidenschaftlich AR-, VR- und Cloud-Technologien, die es uns ermöglichen, mithilfe der gemischten Realität innovative Praktiken zu entwickeln.
Jobs bei Havok:- Sie arbeiten in kleinen Teams mit talentierten Entwicklern
- Sie haben die Möglichkeit, mit neuen Technologien auf einer Vielzahl von Hardwareplattformen und -geräten zu arbeiten.
- Sie arbeiten an der Lösung komplexer technischer Probleme mit guten Aussichten
- Sie werden mit coolen Teams auf der ganzen Welt zusammenarbeiten.
Verantwortlichkeiten
- Entwerfen, entwickeln und testen Sie hochwertigen, effizienten und sauberen C ++ - Code für mehrere Plattformen
- Entwickeln Sie gut skalierbare Azure-Dienste
- Arbeiten Sie direkt mit internen und externen Kunden zusammen, um die Produktentwicklung anzuregen
Qualifikationen
- C ++ - Programmier- und Debugging-Kenntnisse
- Fähigkeit, in einem Team mit einem gemeinsamen Code zu arbeiten
- Erfahrung mit Cloud- und verteilten Servicetechnologien (z. B. Azure Batch, Azure Blob-Speicher, Docker, Telemetrie)
Wird ein Plus sein
- C #, ASP.Net, JavaScript, TypeScript, Reagieren
- Unity, Unreal oder verwandte Spiel-Engines
- Erleben Sie interaktives 3D, AR oder VR
- Netzwerk- und Serverdienste
- Leistungsoptimierung
Sie können mehr erfahren und Ihre Bewerbung
hier oder über
LinkedIn einreichen.