constexpr な fusion::invoke

まぁそんな感じの処理です。
関数の引数を Tuple で渡して評価します。

[ソース]

#define SPROUT_CONFIG_SUPPORT_TEMPORARY_CONTAINER_ITERATION
#include <sprout/tuple.hpp>

template<std::size_t... Indices>
struct index_tuple{};

template<
    std::size_t Start,
    std::size_t Finish,
    std::size_t Step = 1,
    typename Acc = index_tuple<>,
    bool Break = (Start >= Finish)
>
struct index_range{
    typedef Acc type;
};

template<
    std::size_t Start, std::size_t Finish, std::size_t Step,
    std::size_t... Indices
>
struct index_range<Start, Finish, Step, index_tuple<Indices...>, false>
    : index_range<Start + Step, Finish, Step, index_tuple<Indices..., Start>>
{};


namespace aliases{

template<typename T>
using remove_reference = typename std::remove_reference<T>::type;

template<std::size_t Index, typename T>
using tuple_element = typename sprout::tuple_element<Index, T>::type;

template<std::size_t N>
using index_range = typename ::index_range<0, N>::type;

}  // namespace aliases


template<typename F, typename Tuple, std::size_t... Indices>
constexpr auto
invoke_impl(F f, Tuple&& t, index_tuple<Indices...>)
->decltype(f(sprout::tuples::get<Indices>(sprout::forward<Tuple>(t))...)){
    return f(sprout::tuples::get<Indices>(sprout::forward<Tuple>(t))...);
}

template<typename F, typename Tuple,
    typename IndexRange = aliases::index_range<
        sprout::tuple_size<aliases::remove_reference<Tuple>>{}
    >
>
constexpr auto
invoke(F f, Tuple&& t)
->decltype(invoke_impl(f, sprout::forward<Tuple>(t), IndexRange())){
    return invoke_impl(f, sprout::forward<Tuple>(t), IndexRange());
}


#include <sprout/string.hpp>

constexpr int
minus(int a, int b){
    return a - b;
}

struct plus{
    template<typename T, typename U>
    constexpr auto
    operator ()(T&& t, U&& u) const
    ->decltype(std::forward<T>(t) + std::forward<U>(u)){
        return std::forward<T>(t) + std::forward<U>(u);
    }
};

int
main(){
    static_assert(invoke(&minus, sprout::make_tuple(5, 2)) == 3, "");

    constexpr auto t = sprout::make_tuple(
        sprout::to_string("homu"), sprout::to_string("mado")
    );
    static_assert(invoke(plus{}, t) == "homumado", "");
    return 0;
}


標準ライブラリの Tuple が constexpr ではないので、Sprout.Tuple を使用しています。

[コンパイラ]

  • g++ (GCC) 4.7.0 20111210 (experimental)