可以用这种方式使用可变参数 functions/templates 吗?

Possible to use a variadic functions/templates in this way?

我想知道是否可以使用可变参数 functions/templates 来传递可变数量的参数(它们本身是函数的 return 值)可变参数函数。

限制条件:

  1. 没有 STL/Boost/other 个库。
  2. 没有loops/recursion.
  3. 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), /* ... */);

Demo