#include <type_traits>
#include <utility>
#include <array>
#include <iostream>
// Library //////////////////////////////////////////////
// Indexing trick
template <int... Is>
struct seq {};
template <int I, int... Is>
struct gen_seq : gen_seq<I - 1, I - 1, Is...> {};
template <int... Is>
struct gen_seq<0, Is...> : seq<Is...> {};
// -- Helpers
namespace {
// Short-cut to get type. Add rvalue-ref if necessary.
template <class T>
typename std::add_rvalue_reference<T>::type val();
// identity operation on types.
template <class T>
struct id { typedef T type; };
// Type of a reduction. (To make GCC happy)
template <class F, class Arg, class... Args> struct reduced_type;
template <class F, class Arg> struct reduced_type<F, Arg> : id<Arg> {};
template <class F, class A, class B, class... Args>
struct reduced_type<
F, A, B, Args...> : id<decltype(F()(val<A>(),
val<typename reduced_type<
F, B, Args...>::type>()))> {};
// Type list.
template <class... T> struct type_list {};
template <int I, class T, class... Ts>
struct gen_type_list : gen_type_list<I - 1, T, T, Ts...> {};
template <class T, class... Ts>
struct gen_type_list<0, T, Ts...> : type_list<Ts...> {};
// Type of an array reduction. (To make GCC happy)
template <class F, class... Args>
typename reduced_type<F, Args...>::type
arr_reduced_type_impl(F, type_list<Args...>);
template <class F, int N, class Arg>
struct arr_reduced_type
: id<decltype(arr_reduced_type_impl(F(), gen_type_list<N, Arg>()))> {};
}
// -- Argument reduce
// Reduces an argument list by pair-wise application of `Func` beginning from
// the right hand side.
//
// arg_reduce<Func>()(1, 2, 3) --> f(1, f(2, 3)), where f is Func().
template <class Func>
struct arg_reduce {
// Edge condition: Single argument.
template <class Arg>
constexpr Arg operator()(Arg&& arg) const {
return std::forward<Arg>(arg);
}
// Variadic template recursion
template <class Arg, class... Args>
constexpr auto operator()(Arg&& arg, Args&&... args)
const -> typename reduced_type<Func, Arg, Args...>::type {
return Func()(std::forward<Arg>(arg),
operator()(std::forward<Args>(args)...));
}
};
// -- Array reduce
// Reduces an array by pair-wise application of `Func` beginning from
// the right hand side.
//
// arr_reduce<Func>()({{1, 2, 3}}) --> f(1, f(2, 3)), where f is Func().
template <class Func>
struct arr_reduce {
private:
// !!! TODO: Is this the correct way of forwarding arrays?
// const ref version
template <class Arg, std::size_t N, int... Is>
constexpr auto arr_reduce_impl(const std::array<Arg, N> &arr, seq<Is...>)
const -> typename arr_reduced_type<Func, N, Arg>::type {
return arg_reduce<Func>()(std::get<Is>(arr)...);
}
// lvalue ref version
template <class Arg, std::size_t N, int... Is>
constexpr auto arr_reduce_impl(std::array<Arg, N> &&arr, seq<Is...>)
const -> typename arr_reduced_type<Func, N, Arg>::type {
return arg_reduce<Func>()(std::get<Is>(std::move(arr))...);
}
public:
// const ref interface
template <class Arg, std::size_t N>
constexpr auto operator()(const std::array<Arg, N> &arr)
const -> typename arr_reduced_type<Func, N, Arg>::type {
return arr_reduce_impl(arr, gen_seq<N>{});
}
// lvalue ref interface
template <class Arg, std::size_t N>
constexpr auto operator()(std::array<Arg, N> &&arr)
const -> typename arr_reduced_type<Func, N, Arg>::type {
return arr_reduce_impl(std::move(arr), gen_seq<N>{});
}
};
// -- Plus
struct plus {
template <class A, class B>
constexpr auto operator()(A &&a, B &&b)
const -> decltype(std::forward<A>(a) + std::forward<B>(b)) {
return std::forward<A>(a) + std::forward<B>(b);
}
};
// -- Multiplies
struct multiplies {
template <class A, class B>
constexpr auto operator()(A &&a, B &&b)
const -> decltype(std::forward<A>(a) * std::forward<B>(b)) {
return std::forward<A>(a) * std::forward<B>(b);
}
};
// -- Summation
using arg_sum = arg_reduce<plus>;
using arr_sum = arr_reduce<plus>;
// !!! TODO: Why not?
// arg_sum = arg_reduce<plus>();
// arr_sum = arg_reduce<plus>();
// -- Product
using arg_prod = arg_reduce<multiplies>;
using arr_prod = arr_reduce<multiplies>;
// Test ///////////////////////////////////////////////////
int main() {
std::cout << "arg_sum: " << arg_sum()(1) << ", " << arg_sum()(1, 2, 3, 4)
<< std::endl;
std::cout << "arr_sum: " << arr_sum()(std::array<int, 1>{ { 1 } }) << ", "
<< arr_sum()(std::array<int, 4>{ { 1, 2, 3, 4 } }) << std::endl;
std::cout << "arg_prod: " << arg_prod()(1) << ", "
<< arg_prod()(1, 2, 3, 4) << std::endl;
std::cout << "arr_prod: " << arr_prod()(std::array<int, 1>{ { 1 } })
<< ", " << arr_prod()(std::array<int, 4>{ { 1, 2, 3, 4 } })
<< std::endl;
}
I2luY2x1ZGUgPHR5cGVfdHJhaXRzPgojaW5jbHVkZSA8dXRpbGl0eT4KI2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8aW9zdHJlYW0+CgovLyBMaWJyYXJ5IC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8KCi8vIEluZGV4aW5nIHRyaWNrCnRlbXBsYXRlIDxpbnQuLi4gSXM+CnN0cnVjdCBzZXEge307CnRlbXBsYXRlIDxpbnQgSSwgaW50Li4uIElzPgpzdHJ1Y3QgZ2VuX3NlcSA6IGdlbl9zZXE8SSAtIDEsIEkgLSAxLCBJcy4uLj4ge307CnRlbXBsYXRlIDxpbnQuLi4gSXM+CnN0cnVjdCBnZW5fc2VxPDAsIElzLi4uPiA6IHNlcTxJcy4uLj4ge307CgovLyAtLSBIZWxwZXJzCm5hbWVzcGFjZSB7Ci8vIFNob3J0LWN1dCB0byBnZXQgdHlwZS4gQWRkIHJ2YWx1ZS1yZWYgaWYgbmVjZXNzYXJ5Lgp0ZW1wbGF0ZSA8Y2xhc3MgVD4KdHlwZW5hbWUgc3RkOjphZGRfcnZhbHVlX3JlZmVyZW5jZTxUPjo6dHlwZSB2YWwoKTsKLy8gaWRlbnRpdHkgb3BlcmF0aW9uIG9uIHR5cGVzLgp0ZW1wbGF0ZSA8Y2xhc3MgVD4Kc3RydWN0IGlkIHsgdHlwZWRlZiBUIHR5cGU7IH07CgovLyBUeXBlIG9mIGEgcmVkdWN0aW9uLiAgKFRvIG1ha2UgR0NDIGhhcHB5KQp0ZW1wbGF0ZSA8Y2xhc3MgRiwgY2xhc3MgQXJnLCBjbGFzcy4uLiBBcmdzPiBzdHJ1Y3QgcmVkdWNlZF90eXBlOwp0ZW1wbGF0ZSA8Y2xhc3MgRiwgY2xhc3MgQXJnPiBzdHJ1Y3QgcmVkdWNlZF90eXBlPEYsIEFyZz4gOiBpZDxBcmc+IHt9Owp0ZW1wbGF0ZSA8Y2xhc3MgRiwgY2xhc3MgQSwgY2xhc3MgQiwgY2xhc3MuLi4gQXJncz4Kc3RydWN0IHJlZHVjZWRfdHlwZTwKICAgIEYsIEEsIEIsIEFyZ3MuLi4+IDogaWQ8ZGVjbHR5cGUoRigpKHZhbDxBPigpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsPHR5cGVuYW1lIHJlZHVjZWRfdHlwZTwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBGLCBCLCBBcmdzLi4uPjo6dHlwZT4oKSkpPiB7fTsKCi8vIFR5cGUgbGlzdC4KdGVtcGxhdGUgPGNsYXNzLi4uIFQ+IHN0cnVjdCB0eXBlX2xpc3Qge307CnRlbXBsYXRlIDxpbnQgSSwgY2xhc3MgVCwgY2xhc3MuLi4gVHM+CnN0cnVjdCBnZW5fdHlwZV9saXN0IDogZ2VuX3R5cGVfbGlzdDxJIC0gMSwgVCwgVCwgVHMuLi4+IHt9Owp0ZW1wbGF0ZSA8Y2xhc3MgVCwgY2xhc3MuLi4gVHM+CnN0cnVjdCBnZW5fdHlwZV9saXN0PDAsIFQsIFRzLi4uPiA6IHR5cGVfbGlzdDxUcy4uLj4ge307CgovLyBUeXBlIG9mIGFuIGFycmF5IHJlZHVjdGlvbi4gIChUbyBtYWtlIEdDQyBoYXBweSkKdGVtcGxhdGUgPGNsYXNzIEYsIGNsYXNzLi4uIEFyZ3M+CnR5cGVuYW1lIHJlZHVjZWRfdHlwZTxGLCBBcmdzLi4uPjo6dHlwZQphcnJfcmVkdWNlZF90eXBlX2ltcGwoRiwgdHlwZV9saXN0PEFyZ3MuLi4+KTsKdGVtcGxhdGUgPGNsYXNzIEYsIGludCBOLCBjbGFzcyBBcmc+CnN0cnVjdCBhcnJfcmVkdWNlZF90eXBlCiAgICA6IGlkPGRlY2x0eXBlKGFycl9yZWR1Y2VkX3R5cGVfaW1wbChGKCksIGdlbl90eXBlX2xpc3Q8TiwgQXJnPigpKSk+IHt9Owp9CgovLyAtLSBBcmd1bWVudCByZWR1Y2UKLy8gUmVkdWNlcyBhbiBhcmd1bWVudCBsaXN0IGJ5IHBhaXItd2lzZSBhcHBsaWNhdGlvbiBvZiBgRnVuY2AgYmVnaW5uaW5nIGZyb20KLy8gdGhlIHJpZ2h0IGhhbmQgc2lkZS4KLy8KLy8gICAgIGFyZ19yZWR1Y2U8RnVuYz4oKSgxLCAyLCAzKSAgLS0+ICBmKDEsIGYoMiwgMykpLCAgd2hlcmUgZiBpcyBGdW5jKCkuCnRlbXBsYXRlIDxjbGFzcyBGdW5jPgpzdHJ1Y3QgYXJnX3JlZHVjZSB7CiAgICAvLyBFZGdlIGNvbmRpdGlvbjogU2luZ2xlIGFyZ3VtZW50LgogICAgdGVtcGxhdGUgPGNsYXNzIEFyZz4KICAgIGNvbnN0ZXhwciBBcmcgb3BlcmF0b3IoKShBcmcmJiBhcmcpIGNvbnN0IHsKICAgICAgICByZXR1cm4gc3RkOjpmb3J3YXJkPEFyZz4oYXJnKTsKICAgIH0KCiAgICAvLyBWYXJpYWRpYyB0ZW1wbGF0ZSByZWN1cnNpb24KICAgIHRlbXBsYXRlIDxjbGFzcyBBcmcsIGNsYXNzLi4uIEFyZ3M+CiAgICBjb25zdGV4cHIgYXV0byBvcGVyYXRvcigpKEFyZyYmIGFyZywgQXJncyYmLi4uIGFyZ3MpCiAgICAgICAgY29uc3QgLT4gdHlwZW5hbWUgcmVkdWNlZF90eXBlPEZ1bmMsIEFyZywgQXJncy4uLj46OnR5cGUgewogICAgICAgIHJldHVybiBGdW5jKCkoc3RkOjpmb3J3YXJkPEFyZz4oYXJnKSwKICAgICAgICAgICAgICAgICAgIG9wZXJhdG9yKCkoc3RkOjpmb3J3YXJkPEFyZ3M+KGFyZ3MpLi4uKSk7CiAgICB9Cn07CgovLyAtLSBBcnJheSByZWR1Y2UKLy8gUmVkdWNlcyBhbiBhcnJheSBieSBwYWlyLXdpc2UgYXBwbGljYXRpb24gb2YgYEZ1bmNgIGJlZ2lubmluZyBmcm9tCi8vIHRoZSByaWdodCBoYW5kIHNpZGUuCi8vCi8vICAgICBhcnJfcmVkdWNlPEZ1bmM+KCkoe3sxLCAyLCAzfX0pICAtLT4gIGYoMSwgZigyLCAzKSksICB3aGVyZSBmIGlzIEZ1bmMoKS4KdGVtcGxhdGUgPGNsYXNzIEZ1bmM+CnN0cnVjdCBhcnJfcmVkdWNlIHsKICBwcml2YXRlOgogICAgLy8gISEhIFRPRE86IElzIHRoaXMgdGhlIGNvcnJlY3Qgd2F5IG9mIGZvcndhcmRpbmcgYXJyYXlzPwogICAgLy8gY29uc3QgcmVmIHZlcnNpb24KICAgIHRlbXBsYXRlIDxjbGFzcyBBcmcsIHN0ZDo6c2l6ZV90IE4sIGludC4uLiBJcz4KICAgIGNvbnN0ZXhwciBhdXRvIGFycl9yZWR1Y2VfaW1wbChjb25zdCBzdGQ6OmFycmF5PEFyZywgTj4gJmFyciwgc2VxPElzLi4uPikKICAgICAgICBjb25zdCAtPiB0eXBlbmFtZSBhcnJfcmVkdWNlZF90eXBlPEZ1bmMsIE4sIEFyZz46OnR5cGUgewogICAgICAgIHJldHVybiBhcmdfcmVkdWNlPEZ1bmM+KCkoc3RkOjpnZXQ8SXM+KGFycikuLi4pOwogICAgfQogICAgLy8gbHZhbHVlIHJlZiB2ZXJzaW9uCiAgICB0ZW1wbGF0ZSA8Y2xhc3MgQXJnLCBzdGQ6OnNpemVfdCBOLCBpbnQuLi4gSXM+CiAgICBjb25zdGV4cHIgYXV0byBhcnJfcmVkdWNlX2ltcGwoc3RkOjphcnJheTxBcmcsIE4+ICYmYXJyLCBzZXE8SXMuLi4+KQogICAgICAgIGNvbnN0IC0+IHR5cGVuYW1lIGFycl9yZWR1Y2VkX3R5cGU8RnVuYywgTiwgQXJnPjo6dHlwZSB7CiAgICAgICAgcmV0dXJuIGFyZ19yZWR1Y2U8RnVuYz4oKShzdGQ6OmdldDxJcz4oc3RkOjptb3ZlKGFycikpLi4uKTsKICAgIH0KCiAgcHVibGljOgogICAgLy8gY29uc3QgcmVmIGludGVyZmFjZQogICAgdGVtcGxhdGUgPGNsYXNzIEFyZywgc3RkOjpzaXplX3QgTj4KICAgIGNvbnN0ZXhwciBhdXRvIG9wZXJhdG9yKCkoY29uc3Qgc3RkOjphcnJheTxBcmcsIE4+ICZhcnIpCiAgICAgICAgY29uc3QgLT4gdHlwZW5hbWUgYXJyX3JlZHVjZWRfdHlwZTxGdW5jLCBOLCBBcmc+Ojp0eXBlIHsKICAgICAgICByZXR1cm4gYXJyX3JlZHVjZV9pbXBsKGFyciwgZ2VuX3NlcTxOPnt9KTsKICAgIH0KICAgIC8vIGx2YWx1ZSByZWYgaW50ZXJmYWNlCiAgICB0ZW1wbGF0ZSA8Y2xhc3MgQXJnLCBzdGQ6OnNpemVfdCBOPgogICAgY29uc3RleHByIGF1dG8gb3BlcmF0b3IoKShzdGQ6OmFycmF5PEFyZywgTj4gJiZhcnIpCiAgICAgICAgY29uc3QgLT4gdHlwZW5hbWUgYXJyX3JlZHVjZWRfdHlwZTxGdW5jLCBOLCBBcmc+Ojp0eXBlIHsKICAgICAgICByZXR1cm4gYXJyX3JlZHVjZV9pbXBsKHN0ZDo6bW92ZShhcnIpLCBnZW5fc2VxPE4+e30pOwogICAgfQp9OwoKLy8gLS0gUGx1cwpzdHJ1Y3QgcGx1cyB7CiAgICB0ZW1wbGF0ZSA8Y2xhc3MgQSwgY2xhc3MgQj4KICAgIGNvbnN0ZXhwciBhdXRvIG9wZXJhdG9yKCkoQSAmJmEsIEIgJiZiKQogICAgICAgIGNvbnN0IC0+IGRlY2x0eXBlKHN0ZDo6Zm9yd2FyZDxBPihhKSArIHN0ZDo6Zm9yd2FyZDxCPihiKSkgewogICAgICAgIHJldHVybiBzdGQ6OmZvcndhcmQ8QT4oYSkgKyBzdGQ6OmZvcndhcmQ8Qj4oYik7CiAgICB9Cn07CgovLyAtLSBNdWx0aXBsaWVzCnN0cnVjdCBtdWx0aXBsaWVzIHsKICAgIHRlbXBsYXRlIDxjbGFzcyBBLCBjbGFzcyBCPgogICAgY29uc3RleHByIGF1dG8gb3BlcmF0b3IoKShBICYmYSwgQiAmJmIpCiAgICAgICAgY29uc3QgLT4gZGVjbHR5cGUoc3RkOjpmb3J3YXJkPEE+KGEpICogc3RkOjpmb3J3YXJkPEI+KGIpKSB7CiAgICAgICAgcmV0dXJuIHN0ZDo6Zm9yd2FyZDxBPihhKSAqIHN0ZDo6Zm9yd2FyZDxCPihiKTsKICAgIH0KfTsKCi8vIC0tIFN1bW1hdGlvbgp1c2luZyBhcmdfc3VtID0gYXJnX3JlZHVjZTxwbHVzPjsKdXNpbmcgYXJyX3N1bSA9IGFycl9yZWR1Y2U8cGx1cz47Ci8vICEhISBUT0RPOiBXaHkgbm90PwovLyBhcmdfc3VtID0gYXJnX3JlZHVjZTxwbHVzPigpOwovLyBhcnJfc3VtID0gYXJnX3JlZHVjZTxwbHVzPigpOwoKLy8gLS0gUHJvZHVjdAp1c2luZyBhcmdfcHJvZCA9IGFyZ19yZWR1Y2U8bXVsdGlwbGllcz47CnVzaW5nIGFycl9wcm9kID0gYXJyX3JlZHVjZTxtdWx0aXBsaWVzPjsKCgovLyBUZXN0IC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLwoKaW50IG1haW4oKSB7CiAgICBzdGQ6OmNvdXQgPDwgImFyZ19zdW06ICIgPDwgYXJnX3N1bSgpKDEpIDw8ICIsICIgPDwgYXJnX3N1bSgpKDEsIDIsIDMsIDQpCiAgICAgICAgICAgICAgPDwgc3RkOjplbmRsOwogICAgc3RkOjpjb3V0IDw8ICJhcnJfc3VtOiAiIDw8IGFycl9zdW0oKShzdGQ6OmFycmF5PGludCwgMT57IHsgMSB9IH0pIDw8ICIsICIKICAgICAgICAgICAgICA8PCBhcnJfc3VtKCkoc3RkOjphcnJheTxpbnQsIDQ+eyB7IDEsIDIsIDMsIDQgfSB9KSA8PCBzdGQ6OmVuZGw7CiAgICBzdGQ6OmNvdXQgPDwgImFyZ19wcm9kOiAiIDw8IGFyZ19wcm9kKCkoMSkgPDwgIiwgIgogICAgICAgICAgICAgIDw8IGFyZ19wcm9kKCkoMSwgMiwgMywgNCkgPDwgc3RkOjplbmRsOwogICAgc3RkOjpjb3V0IDw8ICJhcnJfcHJvZDogIiA8PCBhcnJfcHJvZCgpKHN0ZDo6YXJyYXk8aW50LCAxPnsgeyAxIH0gfSkKICAgICAgICAgICAgICA8PCAiLCAiIDw8IGFycl9wcm9kKCkoc3RkOjphcnJheTxpbnQsIDQ+eyB7IDEsIDIsIDMsIDQgfSB9KQogICAgICAgICAgICAgIDw8IHN0ZDo6ZW5kbDsKfQo=