我可以在 C++17 中将参数类型分支到参数包吗?

Can I branch on argument type to parameter pack in C++17?

当前(旧)函数调用签名:

        long vmcall(const std::string& function_name,
                    std::vector<address_t> args);

现在因为我只能使用(地址大小的)整数调用来宾,这是一个非常有限的接口,我想扩展它至少也处理浮点值,可能还有其他的,就像这样:

        template <typename... Args>
        long vmcall(const std::string& function_name,
                    Args&&... args);

这将是新的函数签名,取代旧的。

显示 args 向量当前的使用方式:

template <int W>
inline void Machine<W>::setup_call(
        address_t call_addr, address_t retn_addr,
        std::vector<address_t> args)
{
    assert(args.size() <= 8);
    cpu.reg(RISCV::REG_RA) = retn_addr;
    for (size_t arg = 0; arg < args.size(); arg++) {
        cpu.reg(RISCV::REG_ARG0 + arg) = args[arg];
    }
    cpu.jump(call_addr);
}

这个函数是从 vmc​​all 使用 std::move(args) 调用的,它所做的只是将 args 向量中的整数参数增量地复制到整数 CPU 寄存器中。当我想调用一个只接受整数参数的函数时,这很好用。所以,如果我想调用一个函数,比如说,接受一个浮点参数,那么就没有办法做到这一点。这是因为 FP 寄存器是完全独立的,需要以不同的方式处理。

此外,通过 NaN 装箱处理 32 位和 64 位浮点数的方式不同。所以,如果能够区分 float 和 double 就好了。

我一开始就不太擅长模板魔法。如何根据参数包中每个元素的类型进行分支?

在C++17中,遍历参数包的方式是使用逗号fold:

(<expr>, ...); // expr contains Args and/or args

如果单个表达式不够用,可以使用立即调用的 lambda:

([&] {
    <statements> // statements contains Args and/or args
 }(), ...);

将此与 if constexpr 结合您的论点类型:

std::vector<address_t> addr_args;
std::vector<fp_t> fp_args;
([&] {
    if constexpr (std::is_integral_v<Args>)
        addr_args.push_back(args);
    else
        fp_args.push_back(args);
 }(), ...);