Last active
October 4, 2016 12:38
-
-
Save elbeno/95e710c04d56d8cc72ade2e6b2bbe9d5 to your computer and use it in GitHub Desktop.
Folding over a tuple
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
#include <cstddef> | |
#include <cstring> | |
#include <cwctype> | |
#include <functional> | |
#include <iostream> | |
#include <string> | |
#include <tuple> | |
#include <type_traits> | |
#include <utility> | |
using namespace std; | |
template <typename F, typename Z, typename... Ts, std::size_t... Is> | |
decltype(auto) fold(std::index_sequence<Is...>, | |
const std::tuple<Ts...>& t, Z&& z, F&& f) | |
{ | |
// The result type is the same for each function, so just take the first. | |
using result_type = decltype(f(z, get<0>(t))); | |
// The "handler_type" will be a lambda that doesn't capture, so decays to a | |
// function pointer. We will wrap the index in a type (integral_constant) | |
// and unwrap its value inside the lambda to access the right fields. | |
using handler_type = result_type (*)(const std::tuple<Ts...>&, Z&&, F&&); | |
auto make_handler = [] (auto int_const) { | |
return [] (const std::tuple<Ts...>& t, Z&& z, F&& f) -> result_type { | |
constexpr auto I = decltype(int_const)::value; | |
return std::forward<F>(f)(std::forward<Z>(z), std::get<I>(t)); | |
}; | |
}; | |
static handler_type handlers[] = { | |
make_handler(std::integral_constant<size_t, Is>{})... | |
}; | |
for (std::size_t i = 0; i < sizeof...(Is); ++i) | |
{ | |
z = handlers[i](t, std::forward<Z>(z), std::forward<F>(f)); | |
} | |
return std::forward<Z>(z); | |
} | |
template <typename F, typename Z, typename... Ts, std::size_t... Is> | |
decltype(auto) fold(std::index_sequence<Is...>, | |
const std::tuple<Ts...>& t, Z& z, F&& f) | |
{ | |
// The result type is the same for each function, so just take the first. | |
using result_type = decltype(f(z, get<0>(t))); | |
// The "handler_type" will be a lambda that doesn't capture, so decays to a | |
// function pointer. We will wrap the index in a type (integral_constant) | |
// and unwrap its value inside the lambda to access the right fields. | |
using handler_type = result_type (*)(const std::tuple<Ts...>&, Z&, F&&); | |
auto make_handler = [] (auto int_const) { | |
return [] (const std::tuple<Ts...>& t, Z& z, F&& f) -> result_type { | |
constexpr auto I = decltype(int_const)::value; | |
return std::forward<F>(f)(z, std::get<I>(t)); | |
}; | |
}; | |
static handler_type handlers[] = { | |
make_handler(std::integral_constant<size_t, Is>{})... | |
}; | |
for (std::size_t i = 0; i < sizeof...(Is); ++i) | |
{ | |
handlers[i](t, z, std::forward<F>(f)); | |
} | |
return z; | |
} | |
template <typename F, typename Z, typename... Ts> | |
decltype(auto) fold(const tuple<Ts...>& t, Z&& z, F&& f) | |
{ | |
return fold(std::index_sequence_for<Ts...>{}, t, | |
std::forward<Z>(z), | |
std::forward<F>(f)); | |
} | |
size_t string_len(const string& s) { return s.size(); } | |
size_t string_len(const char* s) { return strlen(s); } | |
size_t string_len(bool) { return 1; } | |
size_t string_len(char) { return 1; } | |
template <typename T> | |
size_t string_len(T t) { return to_string(t).size(); } | |
int main() | |
{ | |
auto t = make_tuple("Hello", 3.14, 1729, 'a'); | |
{ | |
auto f = [](ostream& s, const auto& x) -> ostream& { | |
return s << x << '\n'; | |
}; | |
decltype(auto) s = fold(t, cout, f); | |
s << "done" << endl; | |
} | |
{ | |
auto f = [](size_t l, const auto& x) { | |
return l + string_len(x); | |
}; | |
decltype(auto) s = fold(t, size_t{}, f); | |
cout << s << endl; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Maybe I am missing something, but this seems like an overly complicated tuple fold.
Have the user bind things such way that all the fold function needs is the tuple and a function that can be called with each tuple element.