Bri*_*uez 4 c++ template-meta-programming variadic-templates c++14
template<class... Foos> // N = sizeof...(Foos)
template<typename... Args> // M = sizeof...(Args)
void split_and_call(Args&&... args)
{
// Using Python notation here...
Foos[0](*args[:a]); // a = arity of Foos[0]
Foos[1](*args[a:b]); // b-a = arity of Foos[1]
...
Foos[N-1](*args[z:M]); // M-z = arity of Foos[N-1]
}
Run Code Online (Sandbox Code Playgroud)
假设:
Foos都可以调用Foos都是明确的Foos可能具有0的arityArgs 是所用的所有参数类型的串联 Foos这可以在公开Foos和不 公平的情况下完成Args吗?即使我明确地列出了它们,我实际上也不确定该怎么做.
我试图将非递归实例化版本放在一起,但它涉及一些当前不存在的实用程序.
假设我们F需要2 int秒,并且G需要1 int和参数1, 2, 3.
鉴于F,G,tuple(1, 2, 3),index_sequence<0, 1>,index_sequence<2>,我们要调用apply_impl(F{}, tuple(1, 2, 3), index_sequence<0, 1>{})和apply_impl(G{}, tuple(1, 2, 3), index_sequence<2>{}).
扩展F,G简单Fns{}...,并使参数的元组也很简单std::forward_as_tuple(std::forward<Args>(args)...).我们留下来构建index_sequences.
假设我们的函数是arities [2, 1, 3],我们首先得到它的部分和,并在前面加上0:[0, 2, 3, 6].我们希望该指数范围是:[0, 2),[2, 3),[3, 6).
我们拆分[0, 2, 3, 6]成is = [0, 2, 3],并js = [2, 3, 6]和zip他们得到我们想要的范围.
template <typename... Fns, typename Args, std::size_t... Is, std::size_t... Js>
void split_and_call_impl(Args &&args,
std::index_sequence<Is...>,
std::index_sequence<Js...>) {
int dummy[] = {
(apply_impl(Fns{}, std::forward<Args>(args), make_index_range<Is, Js>{}),
0)...};
(void)dummy;
}
template <typename... Fns, typename... Args>
void split_and_call(Args &&... args) {
auto partial_sums = partial_sum_t<0, function_arity<Fns>{}...>{};
auto is = slice<0, sizeof...(Fns)>(partial_sums);
auto js = slice<1, sizeof...(Fns) + 1>(partial_sums);
split_and_call_impl<Fns...>(
std::forward_as_tuple(std::forward<Args>(args)...), is, js);
}
Run Code Online (Sandbox Code Playgroud)
我们需要的apply_impl部分实际上是部分.
template <typename Fn, typename Tuple, size_t... Is>
decltype(auto) apply_impl(Fn &&fn, Tuple &&tuple, std::index_sequence<Is...>) {
return std::forward<Fn>(fn)(std::get<Is>(std::forward<Tuple>(tuple))...);
}
Run Code Online (Sandbox Code Playgroud)
用于确定函数的arity.
template <typename F>
struct function_arity;
template <typename R, typename... Args>
struct function_arity<R (Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)> {};
template <typename R, typename... Args>
struct function_arity<R (*)(Args...)> : function_arity<R (Args...)> {};
template <typename R, typename... Args>
struct function_arity<R (&)(Args...)> : function_arity<R (Args...)> {};
template <typename R, typename C, typename... Args>
struct function_arity<R (C::*)(Args...) const> : function_arity<R (Args...)> {};
template <typename R, typename C, typename... Args>
struct function_arity<R (C::*)(Args...)> : function_arity<R (Args...)> {};
template <typename C>
struct function_arity : function_arity<decltype(&C::operator())> {};
Run Code Online (Sandbox Code Playgroud)
make_index_sequence<N>构造的变体index_sequence<0, .. N>.make_index_range<B, E>构造index_sequence<B, .. E>.
template <typename T, typename U, T Begin>
struct make_integer_range_impl;
template <typename T, T... Ints, T Begin>
struct make_integer_range_impl<T, std::integer_sequence<T, Ints...>, Begin> {
using type = std::integer_sequence<T, Begin + Ints...>;
};
template <class T, T Begin, T End>
using make_integer_range =
typename make_integer_range_impl<T,
std::make_integer_sequence<T, End - Begin>,
Begin>::type;
template <std::size_t Begin, std::size_t End>
using make_index_range = make_integer_range<std::size_t, Begin, End>;
Run Code Online (Sandbox Code Playgroud)
index_sequence在范围内切片[Begin, End).
例如 slice<0, 2>(index_sequence<2, 3, 4, 5>{}) == index_sequence<2, 3>
template <std::size_t... Is, std::size_t... Js>
constexpr decltype(auto) slice_impl(std::index_sequence<Is...>,
std::index_sequence<Js...>) {
using array_t = std::array<std::size_t, sizeof...(Is)>;
return std::index_sequence<std::get<Js>(array_t{{Is...}})...>();
}
template <std::size_t Begin, std::size_t End, std::size_t... Is>
constexpr decltype(auto) slice(std::index_sequence<Is...> is) {
return slice_impl(is, make_index_range<Begin, End>());
}
Run Code Online (Sandbox Code Playgroud)
功能版std::partial_sum.
例如 partial_sum<2, 3, 4> == index_sequence<2, 5, 9>
template <std::size_t... Is>
struct partial_sum;
template <std::size_t... Is>
using partial_sum_t = typename partial_sum<Is...>::type;
template <>
struct partial_sum<> { using type = std::index_sequence<>; };
template <std::size_t I, std::size_t... Is>
struct partial_sum<I, Is...> {
template <typename Js>
struct impl;
template <std::size_t... Js>
struct impl<std::index_sequence<Js...>> {
using type = std::index_sequence<I, Js + I...>;
};
using type = typename impl<partial_sum_t<Is...>>::type;
};
Run Code Online (Sandbox Code Playgroud)
我将分享这部分,因为我进一步玩这个有趣.我不会详细介绍,因为它不是被问到的.
call(fs...)(args...);以便可以传递顶级函数.例如call(f, g)(1, 2, 3)std::tuple.例如auto result = call(f, g)(1, 2, 3)