書き初め

constexpr lambdaが使えるってことは?ということで思いついたネタを。 とりあえずclangさんでは動いてしまった。gccさんは置いてけぼりです。 wandbox.org

proof of conceptなので、必要なオーバーロード全然なかったり勝手にconstついたりする気がするので注意。

#include <iostream>
#include <utility>

static constexpr auto stack = [](auto... xs) constexpr { 
    return [=](auto access) { 
        return access(xs...);
    }; 
};

template <std::size_t N>
struct popper {};

template <typename Type>
struct helper {
    Type data;
    
    template <typename T>
    static constexpr auto make_helper(T&& arg) {
        return helper<std::decay_t<T>>(std::forward<T>(arg));
    }

    static constexpr auto push = [](auto xs, auto x) constexpr {
        return xs([=](auto... z) {
            return [=](auto access) {
                return access(x, z...);
            };
        });
    };

    static constexpr auto pop = [](auto xs) constexpr {
        return xs([=](auto, auto... z) {
            return [=](auto access) {
                return access(z...);
            };
        });
    };

    template <typename T>
    constexpr helper(T&& arg) : data(std::forward<T>(arg)) {};

    template <typename U>
    constexpr auto operator +(const U& rhs) const {
        return helper<Type>::make_helper(push(this->data, rhs.data));
    }
    
    template <typename U>
    constexpr auto operator -(const U&) const {
        return helper<Type>::make_helper(pop(this->data));
    }
};

static constexpr auto top = [](auto xs) constexpr {
    return xs.data([=](auto v, auto...) {
        return v;
    });
};

template <typename T>
    static constexpr auto make_helper(T&& arg) {
        return helper<std::decay_t<T>>(std::forward<T>(arg));
}

template <typename... Types>
struct tuple {
    decltype((make_helper(stack()) + ... + make_helper(std::declval<Types>()))) data;

    template <typename... Ts>
    constexpr tuple(Ts&&... args) : data((make_helper(stack()) + ... + make_helper(std::forward<Ts&&>(args)))) {}
};

template <typename... Types, std::size_t... Indices>
constexpr auto get_impl(const tuple<Types...>& t, std::index_sequence<Indices...>) {
    return (t.data - ... - make_helper(popper<Indices>{}));
}

template <std::size_t N, typename... Types>
constexpr auto get(const tuple<Types...>& t) {
    static_assert(sizeof...(Types) > 0);
    return top(get_impl(t, std::make_index_sequence<(sizeof...(Types) - 1) - N>{}));
}

int main() {
    constexpr tuple<int, char, double, bool> t(1, 'a', 3.14, true);
    static_assert(get<0>(t) == 1);
    static_assert(get<1>(t) == 'a');
    static_assert(get<2>(t) == 3.14);
    static_assert(get<3>(t) == true);
}