二項演算子を前置する遊び


#include <utility>
#include <tuple>

namespace prefix_op {

namespace detail {

template<size_t N, typename T>
typename std::tuple_element<N, T>::type &
get_with_tuple_ref_collapsing(T & tup) {
return std::get<N>(tup);
}
template<size_t N, typename T>
typename std::tuple_element<N, T>::type &&
get_with_tuple_ref_collapsing(T && tup) {
return std::move(std::get<N>(tup));
}

struct adder {
template<typename T, typename U>
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);
}
};

}

struct prefix_op_t {
detail::adder operator+(prefix_op_t) const {
return detail::adder();
}
template<typename T>
auto operator+(T && tup) const
->decltype(detail::get_with_tuple_ref_collapsing<0>(tup)
+ detail::get_with_tuple_ref_collapsing<1>(tup))
{
return detail::get_with_tuple_ref_collapsing<0>(tup)
+ detail::get_with_tuple_ref_collapsing<1>(tup);
}
template<typename T, typename U>
std::tuple<T &&, U &&> operator()(T && t, U && u) const {
return std::tuple<T &&, U &&>(std::forward<T>(t),
std::forward<U>(u));
}
} const _ = {};

}

void f() {
using namespace prefix_op;

_+_(1, 2);
_+_(1, _+_(2, 3));
1 + (_+_(2, 3));
1 + (_+_)(2, 3);

std::plusとかBoost.Lambda使えよ、というのとはまたちょっと違うニーズ…と思っている。まぁお遊びなので気にしないことが一番。ちなみにgcc4.5 lambdas branchの半年ほど前のやつで試してみたところ、「すまんがtemplate_id_exprのマングリングは実装しとらんのだわ」と言わはる。そして今svn updateとかやってる。
追記:template argument deductionの理解を間違えていたようなので、forward使ってるあたりを修正。