Библиотека C++ для компиляции слияния наборов в единый массив


Я построил эту маленькую библиотеку для создания компиляции собран массив из нескольких жестко заданных последовательностей (неравной длины) типа T:

mergeable_set.hpp

#pragma once

template <typename T>
class mergeable {
public:
    template <T... Ts>
    struct set {
        static constexpr T values[] {Ts...};

        constexpr const auto& operator[](const int i) const noexcept { return values[i]; }
        constexpr auto size() const noexcept { return sizeof...(Ts); }

        class iterator {
        public:
            constexpr explicit iterator(set& _ref, const int i = 0) : ref{_ref}, index{i} {}
            constexpr iterator& operator++() noexcept { ++index; return *this; }
            constexpr bool      operator!=(const iterator& other) const noexcept { return index != other.index; }
            constexpr auto&     operator* () noexcept { return ref[index]; }
        private:
            set& ref;
            int index;
        };
        class citerator {
        public:
            constexpr citerator(const set& _ref, const int i) : ref{_ref}, index{i} {}
            constexpr citerator&  operator++() noexcept { ++index; return *this; }
            constexpr bool        operator!=(const citerator& other) const noexcept { return index != other.index; }
            constexpr const auto& operator* () const noexcept { return ref[index]; }
        private:
            const set& ref;
            int index;
        };
        constexpr iterator begin() noexcept { return iterator{*this, 0}; }
        constexpr citerator begin() const noexcept { return citerator{*this, 0}; }
        constexpr iterator end()   noexcept { return iterator{*this, sizeof...(Ts)}; }
        constexpr citerator end()   const noexcept { return citerator{*this, sizeof...(Ts)}; }
    };

private:
    template <typename, typename...> struct concat{};
    template<T... A, T... B>
    struct concat<set<A...>, set<B...>> {
        using type = set<A..., B...>;
    };
    template<T... A>
    struct concat<set<A...>> {
        using type = set<A...>;
    };

    template <typename...> struct _combine {};
    template <typename A, typename B, typename... C>
    struct _combine<A, B, C...> {
        using type = typename concat<A, typename _combine<B, C...>::type>::type;
    };
    template <typename A, typename B>
    struct _combine<A, B> {
        using type = typename concat<A, B>::type;
    };
    template <typename A>
    struct _combine<A> {
        using type = typename concat<A>::type;
    };

public:
    template <typename...U>
    using combine = typename _combine<U...>::type;
};

Использовать такой:

#include "mergeable_set.hpp"

int main() {
    mergeable<int>::set<1, 2, 3> a;
    mergeable<int>::set<4, 5, 6> b;
    mergeable<int>::set<1, 2, 3> c;
    mergeable<int>::set<4, 5, 6> d;
    mergeable<int>::combine<decltype(a),
                            decltype(b),
                            decltype(c),
                            decltype(d)> z;

    int temp = 0;

    for (auto e : z) {
        temp += e;
    }

    volatile int l = temp;
}

С z ведет себя как обычный массив (const int z[12]). Интересно это представляет какие-то странные поведения в GCC. При компиляции x86 код любого массива более 7 элементов создает Симд пакетное добавление инструкции. Хотя это звучит здорово, отключив ГСП на самом деле компилирует все инструкции, прямо до конечного результата. Последнее, очевидно, предпочтительнее. Я просто нажмите здесь логическая ошибка в GCC?

Живой пример этого эффекта: https://godbolt.org/g/4LAJXV Удалить -mno-sse чтобы увидеть разницу.

Я хотел бы услышать, что можно улучшить, чтобы сделать это в более общей библиотеки цели.



Комментарии