Simple TMP Programme



  • Könnt ihr mal Beispiele für simple TMP Programme zeigen?



  • Kannst du mal eine Suchmaschine nach sowas fragen?



  • Kommt nix gescheites, nur sowas.
    http://en.wikibooks.org/wiki/C%2B%2B_Programming/Templates/Template_Meta-Programming#History_of_TMP

    Was für Sachen macht ihr damit?



  • Programmier-Niveau schrieb:

    Was für Sachen macht ihr damit?

    Mal etwas älteres von mir und camper: http://www.c-plusplus.net/forum/p2236280#2236280
    Also eine ROT13-Verschlüsselung von Strings zur Compile-Zeit.

    Ist aber eher für die Lolz. Man kann z. B. auch PI zur Compile-Zeit berechnen 😋


  • Mod

    Hier ein weiteres Spaßbeispiel, dieses Mal etwas altes von mir:
    http://www.c-plusplus.net/forum/p2189560#2189560



  • Ganz einfaches Beispiel:

    #include <iterator>
    #include <list>
    #include <vector>
    
    int main() {
      std::vector<int> v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // Ui, C++11
      std::list  <int> l { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    
      auto iv = v.begin();
      auto il = l.begin();
    
      std::advance(iv, 5); // Ui, TMP
      std::advance(il, 5);
    }
    

    ...worin der Compiler in std::advance die Iterator-Kategorie des übergebenen Iterators ausklamüsert und danach auswählt, auf welche Art der Iterator erhöht wird - im Vektor-Fall iv += 5;, im Listen-Fall for(int i = 0; i < 5; ++i) { ++il; }.

    Aber seldon, höre ich dich sagen, das ist doch so einfach, kann das wirklich TMP sein?

    Albernheiten beiseite, ja, das ist TMP, und es ist ein besseres Anschauungsbeispiel als Fibonacci-Zahlen zur Compilezeit auszurechnen, weil es näher an das herankommt, wofür man TMP wirklich brauchen kann. Wofür will ich den Compiler wirklich ackern lassen? Hauptsächlich, um Entscheidungen im Typsystem zu automatisieren.

    Anderes Beispiel: Ich habe mehrere Kindklassen einer gemeinsamen Basisklasse und weiß an einer Stelle, dass ich eine davon zur Laufzeit instanziieren will. Ich will außerdem den Overhead einer Heap-Allokation vermeiden, weil ich mich in einem Bottleneck befinde. Also grabe ich std::aligned_storage aus und mache den Kram mit placement-new von Hand. Was will ich dem Compiler aufdrücken? Der soll mir die Größe des Speicherplatzes, den ich brauche, und das passende Alignment ausrechnen. Und so kommen wir beispielsweise zu

    namespace const_algo {
      template<typename T> constexpr T max(T x, T y) { return x > y ? x : y; }
      template<typename T> constexpr T min(T x, T y) { return x < y ? x : y; }
    
      namespace impl {
        template<typename T>
        constexpr T lcm_helper(T upper, T lower, T interim) {
          return interim % lower == 0 ? interim : lcm_helper(upper, lower, interim + upper);
        }
      }
    
      template<typename T>
      constexpr T lcm(T x, T y) {
        return impl::lcm_helper(::const_algo::max(x, y),
                                ::const_algo::min(x, y),
                                ::const_algo::max(x, y));
      }
    }
    
    namespace inplace {
      template<typename... types> struct geometry;
    
      template<typename head_type, typename... tail_types>
      struct geometry<head_type, tail_types...> {
        static std::size_t const space     = const_algo::max( sizeof(head_type), geometry<tail_types...>::space    );
        static std::size_t const alignment = const_algo::lcm(alignof(head_type), geometry<tail_types...>::alignment);
      };
    
      template<>
      struct geometry<> {
        static std::size_t const space     = 0;
        static std::size_t const alignment = 1;
      };
    
      ...
    
      template<typename    base_type,
               typename... possible_types>
      struct factory {
        ...
    
        typedef geometry<possible_types...>                                   geometry_type;
        typedef typename std::aligned_storage<geometry_type::space,
                                              geometry_type::alignment>::type storage_type;
    
        storage_type storage_;
    
        ...
      };
    }
    

    Und wenn du jetzt ganz hart bist, kannst du dir mal ankucken, wie die Leute bei Boost.Spirit die Attribute ihrer Parser zur Compilezeit ausrechnen.

    Die Spielereien mit Zahlen und Strings sind ganz nett, und es ist gut, dass so was geht, aber wenn man das ganze ernsthaft betreibt, wirft man die meiste Zeit mit Typen um sich.



  • Na, wenn man sich dafür Interessiert dann gibt es zwei Sachen die man sich ansehen sollte:



  • Boost.Preprocessor ist, wie der Name schon sagt, keine TMP-Bibliothek. Ist aber trotzdem manchmal praktisch, wenn man sich mit alten Compilern herumschlagen muss, die noch keine variadischen Templates kennen.



  • Darf man bei TMP kein if verwenden, sondern nur ? :



  • Alles, was du in TMP benutzt, wird zur Compilezeit ausgewertet, deswegen herrschen da ziemlich strenge Regeln. If-Blöcke sind da nicht erlaubt, nein. Sie könnten auch nur in stark eingeschränkter Form funktionieren.

    Es gibt allerdings Überlegungen, ein static_if (wie in D) einzuführen. Ich sehe nicht, dass das in diesem konkreten Fall sehr sinnvoll wäre, aber in anderen Zusammenhängen könnte das den Code stark vereinfachen. Mal kucken, was daraus wird.




Anmelden zum Antworten