我正在编写一个函数,该函数对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。所以我的问题是我应该担心我的二进制文件在这种情况下会爆炸吗?
最佳答案
忘记在编译时尝试做事情,并且(暂时)忘记性能。一旦确定了实际功能,就可以对该部分进行优化。
在这种情况下,您[似乎要尝试执行的操作]是针对表中的每一行,对两个预定索引进行一系列计算,然后将结果推入向量。我不知道A
或B
如何获取它们的值,因此我的解决方案不会涉及到它们。
我的第一个建议是将整个过程组织成一个可以称为的函数表:
//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/