我正在编写一个函数,该函数对C ++中的大量表数据进行一些计算。该函数应采用“指令”列表,以指定要计算的内容。

例如,表格可以看起来像这样

| A | B | C |
|---|---|---|
| 1 | 2 | 4 |
| 2 | 3 | 5 |
| 3 | 5 | 6 |
|...........|

I am trying to build a function that look like this

std::vector<int> compute(const Table& input, const std::vector<MetricsEnum>& metrics)
{
    std::vector<int> result;
    result.reserve(some heuristic number I put in);
    for(const auto& row: input)
    {
       if(std::find(metrics.begin(), metrics.end(), Metrics1) != metrics.end())
       {
           result.push_back(row[A] + row[B]);
       }
      if(std::find(metrics.begin(), metrics.end(), Metrics2) != metrics.end())
      {
          result.push_back(row[A] - row[B]);
      }
      // this list goes for about 5 or 6 metrics for now, but later I plan to add more
    }
}


因此,我遇到的问题是,显然输入有很多行,并且在循环内执行if语句对我来说现在更像是一种奢侈。我希望能够使用模板在编译时生成一堆函数,并根据我在运行时想要的指标选择其中一个。符合以下条件的东西:

template <bool metrics1, bool metrics2 ...>
std::vector compute(const Table& input>
{
    ...
    if(metrics1)
    {
        result.push_back(row[A] + row[B]);
    }
    if(metrics2)
    {
        result.push_back(row[A] - row[B]);
    }
    ...
}


但是这里有一些问题对我来说很难:


我不确定如何在这里实现我的想法。您能给我指出一些例子吗?我有一种模糊的感觉,认为C ++ 17中的if constexpr可以帮到我。但是很不幸,我仍然在C ++ 11领域,不得不在这里呆一会儿。
更重要的是,我的想法是否值得实施?据我了解,C ++编译器将在编译时生成2 ^ n个函数,其中n是指标数量。就目前而言,这个数目相对较小,但是函数的数目呈指数增长,我很确定n有时会大于10。所以我的问题是我应该担心我的二进制文件在这种情况下会爆炸吗?

最佳答案

忘记在编译时尝试做事情,并且(暂时)忘记性能。一旦确定了实际功能,就可以对该部分进行优化。

在这种情况下,您[似乎要尝试执行的操作]是针对表中的每一行,对两个预定索引进行一系列计算,然后将结果推入向量。我不知道AB如何获取它们的值,因此我的解决方案不会涉及到它们。

我的第一个建议是将整个过程组织成一个可以称为的函数表:

//Replace all instances of 'int' with whatever type you're using
std::vector<int> compute(const Table& input, const std::vector<MetricsEnum>& metrics)
{
    typedef int (*func_ptr_type)(int,int);
    //I'm assuming MetricsEnum is a literal enum type, convertible to an integer.
    static const std::array<func_ptr_type, 6> functions{
        +[](int a, int b) {return a + b;},
        +[](int a, int b) {return a - b;},
        +[](int a, int b) {return a * b;},
        +[](int a, int b) {return a / b;},
        +[](int a, int b) {return a << b;},
        +[](int a, int b) {return a >> b;}
        //Add more and increase the size of the array, as needed
    };
    std::vector<int> result;
    //Don't do this; let the compiler and allocator do their jobs
    //result.reserver(some heuristic number I put in);
    for(const auto& row: input)
    {
        for(MetricsEnum metricsEnum : metrics) {
            result.emplace_back(functions.at(size_t(metrics))(row[A], row[B]));
        }
    }
    return result;
}


通过这种形式,可以更轻松地了解代码的含义,并且还可以使整个事情井井有条。

下一步将是完全消除数组,并使函数成为MetricsEnum类型行为的核心部分,无论是什么。

template<typename T>
class MetricsEnum {
public:
    enum class Type {
        add, subtract, multiply, divide, shift_left, shift_right
    };
    constexpr MetricsEnum(Type type) : type(type) {}

    constexpr T operator()(T a, T b) const {
        switch(type) {
            case Type::add: return a + b;
            case Type::subtract: return a - b;
            case Type::multiply: return a * b;
            case Type::divide: return a / b;
            case Type::shift_left: return a << b;
            case Type::shift_right: return a >> b;
            default: return {};
        }
    }
private:
    Type type;
};

std::vector<int> compute(const Table& input, const std::vector<MetricsEnum<int>>& metrics)
{
    std::vector<int> result;
    for(const auto& row: input)
    {
        for(auto const& metricsEnum : metrics) {
            result.emplace_back(metricsEnum(row[A], row[B]));
        }
    }
    return result;
}


还有许多其他方法可以解决此问题(想到多态性...);这对我来说是最直观的。

关于c++ - 我可以使用模板来控制代码块并确保它不会爆炸吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50864983/

10-11 22:55
查看更多