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]
}
假设:
Foos
中的所有类型都是可调用的Foos
中的所有类型都是明确的Foos
中的任何类型的元数都可以为 0Args
是Foos
使用的所有参数类型的串联
仅使用 Foos
而不使用 Args
是否可以做到这一点?即使我确实明确列出了它们,我实际上也不确定该怎么做。
最佳答案
我试图组合一个非递归实例化版本,但它涉及一些当前不存在的实用程序。
拆分通话
假设我们有 F
这需要 2 int
s 和 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_sequence
假设我们的函数参数是 [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]
并将它们压缩以获得我们想要的范围。
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);
}
实用程序
- std::apply (C++17)
- function_arity
- make_index_range
- 切片
- partial_sum
标准::应用
我们需要的部分实际上是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))...);
}
函数参数
用于确定函数的元数。
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())> {};
制作索引范围
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>;
切片
切片 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>());
}
部分总和
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;
};
奖金
我将分享这一部分,因为我为了好玩而进一步玩这个。我不会讲太多细节,因为这不是要求的内容。
- 将语法更新为
call(fs...)(args...);
这样就可以传递顶级函数。例如call(f, g)(1, 2, 3)
- 将每个函数调用的结果返回为
std::tuple
.例如auto result = call(f, g)(1, 2, 3)
关于c++ - 从函数参数构建模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32288778/