Skip to content

Instantly share code, notes, and snippets.

@cleoold
Last active April 7, 2020 08:59
Show Gist options
  • Save cleoold/90627f0adc1615e09b13b31a4001c8ba to your computer and use it in GitHub Desktop.
Save cleoold/90627f0adc1615e09b13b31a4001c8ba to your computer and use it in GitHub Desktop.
C++ accumulating template arguments
// -std=c++17 (auto parameter, inline variable)
// x64msvc>=v19.20, x64clang>=5.0.0, x64gcc>=8.1
#include <utility> // integer_sequence
namespace num {
template <typename T, T n>
struct _pack {
using type = _pack;
using value_type = T;
static constexpr T value = n;
};
template<auto n>
struct pack
: _pack<decltype(n), n> {};
namespace methodone {
template<template<typename, typename> typename F, typename T, typename U, T a, U b>
struct _apply
: pack<F<T, U>::template value<a, b>>
{};
template<template<typename, typename> typename, auto...>
struct accumulate;
template<template<typename, typename> typename F, auto a, auto b>
struct accumulate<F, a, b>
: _apply<F, decltype(a), decltype(b), a, b>
{};
template<template<typename, typename> typename F, auto a, auto b, auto ...nn>
struct accumulate<F, a, b, nn...>
: accumulate<F, accumulate<F, a, b>::value, nn...>
{};
}
namespace methodtwo {
template<template<typename, typename> typename, typename...>
struct _accumulate;
template<template<typename, typename> typename F, typename A, typename B>
struct _accumulate<F, A, B>
: pack<F<typename A::value_type, typename B::value_type>::template value<A::value, B::value>>
{};
template<template<typename, typename> typename F, typename A, typename B, typename ...Nn>
struct _accumulate<F, A, B, Nn...>
: _accumulate<F, typename pack<_accumulate<F, A, B>::value>::type, Nn...>
{};
// <= gcc 7.5:
// after defining b in main using methodtwo, c becomes unsigned using methodtwo, which is wrong
// is this a bug?
template<template<typename, typename> typename F, auto ...nn>
struct accumulate
: _accumulate<F, typename pack<nn>::type...>
{};
}
#define GENBIOPS(NAME, EXPR) \
template<typename T, typename U> \
struct NAME { \
template<T a, U b> static inline constexpr decltype(EXPR) value = EXPR; \
};
GENBIOPS(add, a + b)
GENBIOPS(mul, a * b)
GENBIOPS(lor, a || b)
GENBIOPS(land, a && b)
#undef GENBIOPS
} // namespace num
template<typename> struct sum_of_int_sequence;
template<int ...N> struct sum_of_int_sequence<std::integer_sequence<int, N...>>
: num::methodone::accumulate<num::add, N...>
{};
int main(void) {
const auto a = num::methodone::accumulate<num::add, 'a', 2U, 4ULL, 6>::value;
static_assert(a == 109ULL);
const auto b = num::methodtwo::accumulate<num::add, 'a', 2U, 4ULL, 6>::value;
static_assert(b == 109ULL);
const auto c = num::methodtwo::accumulate<num::mul, -1, 2, 3, 4, 5>::value;
static_assert(c == -120);
const auto d = num::methodone::accumulate<num::lor, false, false, true, false>::value;
static_assert(d == true);
const auto e = sum_of_int_sequence<std::make_integer_sequence<int, 100+1>>::value;
static_assert(e == 5050);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment