【问题标题】:Dynamic dispatch function call with variadic arguments带可变参数的动态调度函数调用
【发布时间】:2021-08-31 13:14:37
【问题描述】:

我有一些函数来支持它们都采用同质参数。但是每个函数可以采用不同的数量。 这些函数通过指定函数名及其参数来调用。

例子,

#include <iostream>
#include <vector>
#include <cmath>

enum class operation{
    abs,
    add,
    ceil,
    floor,
    sub
};

template <typename... T>
int foo(operation op, const T&... args){
    
    std::vector<int> operands({args...});
    
    switch(op){
        case operation::abs:
            return abs(operands[0]);
        case operation::add:
            return operands[0] + operands[1];
        case operation::ceil:
            return ceil(operands[0]);
        case operation::floor:
            return floor(operands[0]);
        case operation::sub:
            return operands[0] - operands[1];
    }
}

int main() {
    
    // operation is a user input at runtime
    operation op = operation::add;
    
    // call foo with some arguments
    std::cout << foo(op, 5, 6);
    
    return 0;
}

这有一定的问题:

  1. 使用向量,因此存在不必要的堆分配。
  2. 代码膨胀,因为所有操作都是针对不同数量的参数编译的。
  3. 一个非常大的 if/else,因为我不断添加操作。

大多数相关问题都使用函数对象和模板来解决这个问题。但是这里的操作是未知的编译时间常数。

有没有更好的方法来做到这一点,而不必为 foo 的所有实例中的所有操作编译代码?

【问题讨论】:

  • 如何直到运行时才知道操作,但在编译时知道操作的参数?
  • 12 可以通过不使用单个可变参数函数来解决,而是每个参数一个函数:foo(op, arg) 处理单参数运算符,foo(op, arg1, arg2) 处理两个-参数的。 3 可以通过维护从 operation 值到函数指针的映射来解决(可能再次单独映射每个参数)。

标签: c++ c++14 metaprogramming variadic-templates variadic-functions


【解决方案1】:

https://godbolt.org/z/aKxsb18qe

#include <iostream>
#include <vector>
#include <cmath>

enum class operation{
    abs,
    add,
    ceil,
    floor,
    sub
};

template <typename T, typename... J>
inline __attribute__((always_inline)) T GetFirstPack(T t, J... j)
{
    return t;
}

template <typename T1, typename... T>
int foo(operation op, const T1& arg, const T&... args){
    if constexpr (sizeof...(args) == 0)
    {
        switch(op)
        {
            case operation::abs:
                return abs(arg);
            case operation::ceil:
                return ceil(arg);
            case operation::floor:
                return floor(arg);
        }
    }
    else
    {
        switch(op){
            case operation::add:
                return arg + GetFirstPack(args...);

            case operation::sub:
                return arg - GetFirstPack(args...);
        }
    }
}

int main() {
    
    // operation is a user input at runtime
    operation op = operation::add;
    
    // call foo with some arguments
    std::cout << foo(op, 5, 6);
    
    return 0;
}

【讨论】:

    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-31
    • 2020-06-05
    • 1970-01-01
    相关资源
    最近更新 更多