C++Guns – RoboBlog

27.02.2018

C++ Guns: Templated class specialization where template argument is a template

Filed under: Allgemein — Tags: — Thomas @ 16:02

Okay das ist mit Abstand das krasseste was ich seit langem mit Templates gemacht habe, obwohl die Aufgabe doch recht klar und einfach ist. Der Code ist von der Syntax her auch noch irgendwo okay. Naja, vllt. auch nicht.

Ich habe meine Experimentelle Graph Klasse mit entsprechenden Iteratoren. Datencontainer und Algorithmus trennen und mit Iteratoren wieder verbinden klappt btw. ziemlich gut. Da hat er 1984 was richtig gemacht.

Seit C++17 gibt es std::distance(first, last) welche die Anzahl der Elemente zwischen first und last zurück gibt. Die möchte ich nutzen. Dazu müssen meine Iteratoren std kompatibel werden. Genauer gesagt müssen die Anforderungen an einem InputIterator erfüllt werden. Hierfür muss man std::iterator_traits spezialisieren. Und die 5 Variablen difference_type, value_type, pointer, reference, iterator_category erstellen und auch hoffentlich richtig belegen.

Funktionen im std namespace zu überladen, oder template zu spezialisieren ist in der Regel nicht erlaubt, aber bei std::iterator_trais explizit gewünscht. Man muss nur darauf achten den Code nicht in irgendeinem Namespace zu schreiben, sonst wird er vom Compiler nicht gefunden.

#include <iterator>

template<>
struct std::iterator_traits<MyIterator> {
    using Iterator          = ...;
    using difference_type   = ...;
    using value_type        = ...;
    using pointer           = ...;
    using reference         = ...;
    using iterator_category = ...;
};

So weit so einfach, dumm nur, wenn die Klasse MyIterator wiederrum eine Template Klasse ist. Also braucht man eine Template Klassen Spezialisierung mit einer Template Klasse. Okay das ist schon halb WTF. Wir wollen also ein Template spezialisieren, so dass die Template Parameter gesetzt sind, aber die Parameter sind selbst wieder Template. Die Spezialisierung ist also garnicht speziell, nur ein bisschen.

Wenn man am Ende noch an das Keyword typename denkt (der Compiler erinnert einem gut daran), da wir ja alles vertemplated haben, schaut es am Ende so aus:

template<typename Graph>
struct std::iterator_traits<cpl::graph::ConnNodeIterator<Graph>> {
    using Iterator = cpl::graph::ConnNodeIterator<Graph>;
    using difference_type   = typename Iterator::difference_type;
    using value_type        = typename Iterator::value_type;
    using pointer           = typename Iterator::pointer;
    using reference         = typename Iterator::reference;
    using iterator_category = typename Iterator::iterator_category;
};

Update: Habe nochmal nachgeschaut. Eine Template Spezialisierung beginnt normalerweise mit template<>. Aber in diesem Fall muss man das template<> mit Parameter füllen. Die Spezialisierung funktioniert dennoch :D

Alles nur damit ich das hier so bequem schreiben kann:

NodeID ID = 0;
graph.connNodeRange(ID).size();

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress