Metaprogramming in C++ and in D

后端 未结 10 1933
生来不讨喜
生来不讨喜 2021-01-30 04:46

The template mechanism in C++ only accidentally became useful for template metaprogramming. On the other hand, D\'s was designed specifically to facilitate this. And apparently

10条回答
  •  旧巷少年郎
    2021-01-30 05:30

    Here's a piece of D code that does a custom-made map() which returns its results by reference.

    It creates two arrays of length 4, maps each corresponding pair of elements to the element with the minimum value, and multiplies it by 50, and stores the result back into the original array.

    Some important features to note are the following:

    • The templates are variadic: map() could take any number of arguments.

    • The code is (relatively) short! The Mapper structure, which is the core logic, is only 15 lines -- and yet it can do so much with so little. My point isn't that this is impossible in C++, but that certainly isn't as compact and clean.


    import std.metastrings, std.typetuple, std.range, std.stdio;
    
    void main() {
        auto arr1 = [1, 10, 5, 6], arr2 = [3, 9, 80, 4];
    
        foreach (ref m; map!min(arr1, arr2)[1 .. 3])
            m *= 50;
    
        writeln(arr1, arr2); // Voila! You get:  [1, 10, 250, 6][3, 450, 80, 4]
    }
    
    auto ref min(T...)(ref T values) {
        auto p = &values[0];
        foreach (i, v; values)
            if (v < *p)
                p = &values[i];
        return *p;
    }
    
    Mapper!(F, T) map(alias F, T...)(T args) { return Mapper!(F, T)(args); }
    
    struct Mapper(alias F, T...) {
        T src;  // It's a tuple!
    
        @property bool empty() { return src[0].empty; }
    
        @property auto ref front() {
            immutable sources = FormatIota!(q{src[%s].front}, T.length);
            return mixin(Format!(q{F(%s)}, sources));
        }
    
        void popFront() { foreach (i, x; src) { src[i].popFront(); } }
    
        auto opSlice(size_t a, size_t b) {
            immutable sliced = FormatIota!(q{src[%s][a .. b]}, T.length);
            return mixin(Format!(q{map!F(%s)}, sliced));
        }
    }
    
    
    // All this does is go through the numbers [0, len),
    // and return string 'f' formatted with each integer, all joined with commas
    template FormatIota(string f, int len, int i = 0) {
        static if (i + 1 < len)
            enum FormatIota = Format!(f, i) ~ ", " ~ FormatIota!(f, len, i + 1);
        else
            enum FormatIota = Format!(f, i);
    }
    

提交回复
热议问题