Last active
April 7, 2020 08:59
-
-
Save cleoold/90627f0adc1615e09b13b31a4001c8ba to your computer and use it in GitHub Desktop.
C++ accumulating template arguments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// -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