可以用这种方式使用可变参数 functions/templates 吗?
Possible to use a variadic functions/templates in this way?
我想知道是否可以使用可变参数 functions/templates 来传递可变数量的参数(它们本身是函数的 return 值)可变参数函数。
限制条件:
- 没有 STL/Boost/other 个库。
- 没有loops/recursion.
- C++17 或更早版本兼容(不超过 C++17)。
简要示例:
using fn = F(...);
fn* func = (fn*) addr;
value = (*func)(pop_t(outputstack,o_stackidx,o_stacksize)...);
push_t(outputstack,o_stackidx,o_stacksize, value);
fn*
是一个函数指针(从已知的用户定义的函数内存地址转换而来),它接受可变数量的 pop_t 个参数(从堆栈弹出的值),这些值 (outputstack,o_stackidx,o_stacksize) 是静态的,不需要本身是可变的。本质上,我想知道是否有可能让 pop_t 函数重复可变次数 A.) 取决于适当数量的参数 fn
能够接受或 B.) 使用 a指定重复次数的用户定义整数。
举个例子,假设用户要输入一个 sin 或 atan2 函数,这两个函数采用不同数量的参数,分别是 sin(x) 和 atan(y,x)。对于这两个各自的函数,函数调用表达式如下所示:
sin -> (*func)(pop_t(outputstack,o_stackidx,o_stacksize));
atan2 -> (*func)(pop_t(outputstack,o_stackidx,o_stacksize),pop_t(outputstack,o_stackidx,o_stacksize));
具有 N 个参数的函数通过调用 pop_t
N 次从堆栈中弹出 N 个值。
可重现的例子:
template<class U, class I>
U pop_t(U* stack, I &stackidx, I &stacksize) {
if(stacksize>0) {
stacksize--;
stackidx = stackidx--;
return stack[stackidx];
}
else {
return stack[stackidx];
}
}
int main() {
float outputstack[2] = {3.141/2,1};
int o_stackidx = 2;
int o_stacksize = 2;
long addr = (long)&atan2;
using fn = float(...);
fn* func = (fn*) addr;
// Unknown variadic function pointer
float value = (*func)(pop_t(outputstack,o_stackidx,o_stacksize,nt)...);
return 0;
}
看来你想根据参数的个数多次重复一条语句,那你可以借助C++模板:
#include <cstddef>
#include <utility>
template <size_t N>
struct repeater {
template <typename F, typename ...Args>
static void do_work(F&& f, Args&&... args) {
f(std::forward<Args>(args)...);
repeater<N - 1>::do_work(f, args...);
}
};
template <>
struct repeater<0> {
template <typename F, typename ...Args>
static void do_work(F&&, Args&&...) {}
};
template <size_t N, typename F, typename ...Args2>
void repeat_for_n(F&& to_rep, Args2&&... args) {
repeater<N>::do_work(to_rep, args...);
}
template <typename T1, typename ...Args1, typename F, typename ...Args2>
void repeat_for_args(T1(Args1...), F&& to_rep, Args2&&... args) {
repeat_for_n<sizeof...(Args1)>(to_rep, args...);
}
然后你可以像这样使用它:
repeat_for_args(some_function, [&]() {
(*func)(pop_t(outputstack,o_stackidx,o_stacksize))
});
如果您想先自己尝试一下:
编辑 1: 要在模板的帮助下生成参数中具有 N
重复类型的函数指针类型,您可以这样做:
首先,你需要定义这个助手class:
#include <tuple>
template <typename, typename>
struct make_sig_from_tuple;
template <typename R, typename ...Args>
struct make_sig_from_tuple<R, std::tuple<Args...>> {
using type = R(*)(Args...);
};
template <typename R, typename ...Args>
using make_sig_from_tuple_t = typename make_sig_from_tuple<R, Args...>::type;
然后我们可以这样做,
template <typename T, size_t N>
struct generate_sig_impl {
using type = decltype(std::tuple_cat(std::declval<std::tuple<T>&>(), std::declval<typename generate_sig_impl<T, N - 1>::type&>()));
};
template <typename T>
struct generate_sig_impl<T, 0> {
using type = std::tuple<>;
};
template <typename R, typename T, size_t N>
struct generate_sig {
using type = make_sig_from_tuple_t<R, typename generate_sig_impl<T, N>::type>;
};
template <typename R, typename T, size_t N>
using generate_sig_t = typename generate_sig<R, T, N>::type;
现在可以使用它来转换仅具有 N
值的可变参数函数,而无需多次显式声明类型中的参数:
repeat_for_args(reinterpret_cast<generate_sig_t<float, float, 3>>(function_with_variadic_arguments), /* ... */);
// Equivalent to: repeat_for_args(reinterpret_cast<float(*)(float, float, float)>(function_with_variadic_arguments), /* ... */);
编辑2:由于评论中的OP也想颠倒参数的顺序,可以使用这个:
template <typename Arg1, typename ...Args>
struct reverse_func_sig_impl {
using type = decltype(std::tuple_cat(std::declval<typename reverse_func_sig_impl<Args...>::type&>(), std::declval<std::tuple<Arg1>&>()));
};
template <typename Arg1>
struct reverse_func_sig_impl<Arg1> {
using type = std::tuple<Arg1>;
};
template <typename>
struct reverse_func_sig;
template <typename R, typename... Args>
struct reverse_func_sig<R(Args...)> {
using type = make_sig_from_tuple_t<R, typename reverse_func_sig_impl<Args...>::type>;
};
template <typename FuncPtr>
using reverse_func_sig_t = typename reverse_func_sig<FuncPtr>::type;
然后像这样使用它:
repeat_for_args(reinterpret_cast<generate_sig_t<int(float, int)>>(function_with_variadic_arguments), /* ... */);
// Equivalent to: repeat_for_args(reinterpret_cast<int(int, float)>(function_with_variadic_arguments), /* ... */);
我想知道是否可以使用可变参数 functions/templates 来传递可变数量的参数(它们本身是函数的 return 值)可变参数函数。
限制条件:
- 没有 STL/Boost/other 个库。
- 没有loops/recursion.
- C++17 或更早版本兼容(不超过 C++17)。
简要示例:
using fn = F(...);
fn* func = (fn*) addr;
value = (*func)(pop_t(outputstack,o_stackidx,o_stacksize)...);
push_t(outputstack,o_stackidx,o_stacksize, value);
fn*
是一个函数指针(从已知的用户定义的函数内存地址转换而来),它接受可变数量的 pop_t 个参数(从堆栈弹出的值),这些值 (outputstack,o_stackidx,o_stacksize) 是静态的,不需要本身是可变的。本质上,我想知道是否有可能让 pop_t 函数重复可变次数 A.) 取决于适当数量的参数 fn
能够接受或 B.) 使用 a指定重复次数的用户定义整数。
举个例子,假设用户要输入一个 sin 或 atan2 函数,这两个函数采用不同数量的参数,分别是 sin(x) 和 atan(y,x)。对于这两个各自的函数,函数调用表达式如下所示:
sin -> (*func)(pop_t(outputstack,o_stackidx,o_stacksize));
atan2 -> (*func)(pop_t(outputstack,o_stackidx,o_stacksize),pop_t(outputstack,o_stackidx,o_stacksize));
具有 N 个参数的函数通过调用 pop_t
N 次从堆栈中弹出 N 个值。
可重现的例子:
template<class U, class I>
U pop_t(U* stack, I &stackidx, I &stacksize) {
if(stacksize>0) {
stacksize--;
stackidx = stackidx--;
return stack[stackidx];
}
else {
return stack[stackidx];
}
}
int main() {
float outputstack[2] = {3.141/2,1};
int o_stackidx = 2;
int o_stacksize = 2;
long addr = (long)&atan2;
using fn = float(...);
fn* func = (fn*) addr;
// Unknown variadic function pointer
float value = (*func)(pop_t(outputstack,o_stackidx,o_stacksize,nt)...);
return 0;
}
看来你想根据参数的个数多次重复一条语句,那你可以借助C++模板:
#include <cstddef>
#include <utility>
template <size_t N>
struct repeater {
template <typename F, typename ...Args>
static void do_work(F&& f, Args&&... args) {
f(std::forward<Args>(args)...);
repeater<N - 1>::do_work(f, args...);
}
};
template <>
struct repeater<0> {
template <typename F, typename ...Args>
static void do_work(F&&, Args&&...) {}
};
template <size_t N, typename F, typename ...Args2>
void repeat_for_n(F&& to_rep, Args2&&... args) {
repeater<N>::do_work(to_rep, args...);
}
template <typename T1, typename ...Args1, typename F, typename ...Args2>
void repeat_for_args(T1(Args1...), F&& to_rep, Args2&&... args) {
repeat_for_n<sizeof...(Args1)>(to_rep, args...);
}
然后你可以像这样使用它:
repeat_for_args(some_function, [&]() {
(*func)(pop_t(outputstack,o_stackidx,o_stacksize))
});
如果您想先自己尝试一下:
编辑 1: 要在模板的帮助下生成参数中具有 N
重复类型的函数指针类型,您可以这样做:
首先,你需要定义这个助手class:
#include <tuple>
template <typename, typename>
struct make_sig_from_tuple;
template <typename R, typename ...Args>
struct make_sig_from_tuple<R, std::tuple<Args...>> {
using type = R(*)(Args...);
};
template <typename R, typename ...Args>
using make_sig_from_tuple_t = typename make_sig_from_tuple<R, Args...>::type;
然后我们可以这样做,
template <typename T, size_t N>
struct generate_sig_impl {
using type = decltype(std::tuple_cat(std::declval<std::tuple<T>&>(), std::declval<typename generate_sig_impl<T, N - 1>::type&>()));
};
template <typename T>
struct generate_sig_impl<T, 0> {
using type = std::tuple<>;
};
template <typename R, typename T, size_t N>
struct generate_sig {
using type = make_sig_from_tuple_t<R, typename generate_sig_impl<T, N>::type>;
};
template <typename R, typename T, size_t N>
using generate_sig_t = typename generate_sig<R, T, N>::type;
现在可以使用它来转换仅具有 N
值的可变参数函数,而无需多次显式声明类型中的参数:
repeat_for_args(reinterpret_cast<generate_sig_t<float, float, 3>>(function_with_variadic_arguments), /* ... */);
// Equivalent to: repeat_for_args(reinterpret_cast<float(*)(float, float, float)>(function_with_variadic_arguments), /* ... */);
编辑2:由于评论中的OP也想颠倒参数的顺序,可以使用这个:
template <typename Arg1, typename ...Args>
struct reverse_func_sig_impl {
using type = decltype(std::tuple_cat(std::declval<typename reverse_func_sig_impl<Args...>::type&>(), std::declval<std::tuple<Arg1>&>()));
};
template <typename Arg1>
struct reverse_func_sig_impl<Arg1> {
using type = std::tuple<Arg1>;
};
template <typename>
struct reverse_func_sig;
template <typename R, typename... Args>
struct reverse_func_sig<R(Args...)> {
using type = make_sig_from_tuple_t<R, typename reverse_func_sig_impl<Args...>::type>;
};
template <typename FuncPtr>
using reverse_func_sig_t = typename reverse_func_sig<FuncPtr>::type;
然后像这样使用它:
repeat_for_args(reinterpret_cast<generate_sig_t<int(float, int)>>(function_with_variadic_arguments), /* ... */);
// Equivalent to: repeat_for_args(reinterpret_cast<int(int, float)>(function_with_variadic_arguments), /* ... */);