我偶尔发现在我的代码中,我会有一个数据结构,我想从中获取两个或多个值,每个值都可以使用标准算法提取。问题是,使用标准算法意味着对数据进行多次循环。以下面的示例为例,其中我有一个vector<int>
,并且想要获取总和,第一个元素的值超过某个阈值以及该阈值之上的元素总数:
constexpr auto GetValuesSTL(const std::vector<int>& testdata)
{
constexpr auto value_above_threshold = [](const auto value) constexpr { return value > THRESHOLD; };
constexpr auto optional_from_iterator = [](const auto it, const auto end) constexpr { return it != end ? std::make_optional(*it) : std::nullopt; };
return std::make_tuple(
std::accumulate(testdata.begin(), testdata.end(), 0L),
optional_from_iterator(std::find_if(testdata.begin(), testdata.end(), value_above_threshold), testdata.end()),
std::count_if(testdata.begin(), testdata.end(), value_above_threshold) );
}
但是我可以更有效地将其编写为原始循环:
constexpr auto GetValuesRawLoop(const std::vector<int>& testdata)
{
auto sum = 0L;
std::optional<int> first_above_threshold = std::nullopt;
auto num_above_threshold = 0;
auto it = testdata.begin();
for (; it != testdata.end(); ++it)
{
const auto value = *it;
if (value > THRESHOLD)
{
first_above_threshold = value;
break;
}
sum += value;
}
for (; it != testdata.end(); ++it)
{
const auto value = *it;
sum += value;
if (value > THRESHOLD)
{
++num_above_threshold;
}
}
return std::make_tuple( sum, first_above_threshold, num_above_threshold );
}
我希望编译器能够将算法调用融合到一个循环中,因为它具有足够的信息来知道向量没有被修改,而是在随机生成的整数的各种长度向量上对这两个函数进行了分析(与g++-9 -O3
编译)显示,该函数的STL版本持续花费原始循环的时间大约是2-2.5倍,这与不使用循环融合所期望的完全相同。]
是否有充分的理由编译器不能/不应用这种优化?是否需要某种假设才能融合不允许编译器进行的循环?还是检测和应用根本上困难的事情?有没有其他替代方法可以像原始循环一样有效,并且可以像算法版本一样表现力?
我偶尔发现在我的代码中,我会有一个数据结构,我想从中获取两个或多个值,每个值都可以使用标准算法提取。问题是,要使用...
我将回答您问题的最后一部分: