Skip to content

Instantly share code, notes, and snippets.

@un1tz3r0
Forked from elbeno/for_each_args.cpp
Created May 20, 2021 10:48
Show Gist options
  • Save un1tz3r0/a59a9b0c70d53a7565978f77a1735432 to your computer and use it in GitHub Desktop.
Save un1tz3r0/a59a9b0c70d53a7565978f77a1735432 to your computer and use it in GitHub Desktop.
Functions that work over their arguments
//------------------------------------------------------------------------------
// A function that will apply a function to each argument
#include <initializer_list>
#include <utility>
template <typename F, typename... Ts>
void for_each_arg(F&& f, Ts&&... ts)
{
using I = std::initializer_list<int>;
(void) I { (std::forward<F>(f)(std::forward<Ts>(ts)), 0)... };
}
//------------------------------------------------------------------------------
// Sample application: make_vector
#include <vector>
template <typename T, typename... Ts>
auto make_vector(T&& t, Ts&&... ts)
{
std::vector<T> v;
v.reserve(1 + sizeof...(Ts));
for_each_arg([&v] (auto&& x)
{ v.emplace_back(std::forward<decltype(x)>(x)); },
std::forward<T>(t),
std::forward<Ts>(ts)...);
return v;
}
//------------------------------------------------------------------------------
// Sample application: apply a function to each element of a tuple
#include <tuple>
#include <type_traits>
// Here's the standard way to apply a function to a tuple of args
template<typename F, typename T, size_t... Is>
decltype(auto) apply_impl(F&& f, T&& t, std::index_sequence<Is...>)
{
return std::forward<F>(f)(std::get<Is>(std::forward<T>(t))...);
}
template<typename F, typename T>
decltype(auto) apply(F&& f, T&& t)
{
using Is = std::make_index_sequence<std::tuple_size<std::decay_t<T>>::value>;
return apply_impl(std::forward<F>(f), std::forward<T>(t), Is{});
}
template <typename F, typename T>
void for_each_in_tuple(F&& f, T&& t)
{
apply([&f] (auto&&... xs)
{ for_each_arg(f, std::forward<decltype(xs)>(xs)...); },
std::forward<T>(t));
}
//------------------------------------------------------------------------------
// A function that will apply a function to each group of N args
namespace detail
{
template<typename, typename> struct ForEachNArgsImpl;
template<std::size_t... Bs, std::size_t... Cs>
struct ForEachNArgsImpl<std::index_sequence<Bs...>,
std::index_sequence<Cs...>>
{
template<typename F, typename T>
static void exec(F&& f, T&& t)
{
using I = std::initializer_list<int>;
(void) I { (execN<Bs * sizeof...(Cs)>(std::forward<F>(f),
std::forward<T>(t)), 0)... };
}
template<std::size_t N, typename F, typename T>
static void execN(F&& f, T&& t)
{
std::forward<F>(f)(std::get<N + Cs>(std::forward<T>(t))...);
}
};
}
template<std::size_t N, typename F, typename... Ts>
void for_each_n_args(F&& f, Ts&&... ts)
{
static_assert(sizeof...(Ts) % N == 0,
"for_each_n_args: number of args must be a multiple of the function arity");
detail::ForEachNArgsImpl<std::make_index_sequence<sizeof...(Ts)/N>,
std::make_index_sequence<N>>
::exec(std::forward<F>(f),
std::forward_as_tuple(std::forward<Ts>(ts)...));
}
//------------------------------------------------------------------------------
// Sample application: make_unordered_map
#include <unordered_map>
template<typename K, typename V, typename... Ts>
auto make_unordered_map(K&& k, V&& v, Ts&&... ts)
{
static_assert(sizeof...(Ts) % 2 == 0,
"make_unordered_map requires an even number of arguments");
std::unordered_map<K, V> m;
m.reserve(1 + (sizeof...(Ts) / 2));
for_each_n_args<2>(
[&m](auto&& k, auto&& v)
{
m.emplace(std::forward<decltype(k)>(k),
std::forward<decltype(v)>(v));
},
std::forward<K>(k),
std::forward<V>(v),
std::forward<Ts>(ts)...);
return m;
}
//------------------------------------------------------------------------------
#include <iostream>
#include <string>
int main()
{
using namespace std::string_literals;
// Produces 012
auto v = make_vector(0,1,2);
std::cout << v[0] << v[1] << v[2] << std::endl;
// Produces 012
auto m = make_unordered_map(
"zero"s, 0,
"one"s, 1,
"two"s, 2);
std::cout << m["zero"] << m["one"] << m["two"] << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment