我遇到过(和编写过的)代码,其中布尔关系表达式中标准模板库的自然使用会导致(可能)浪费精力。
例如,
if (std::distance(begin, end) <= 2) { ... }
或者:
if (std::count(begin,end,val) >= 3) { ... }
在这两种情况下,可以编写自定义算法,以避免在部分评估范围后知道答案时进行不必要的迭代/评估。
是否有一种通用方法可用于防止在这些情况下浪费精力?
编辑:尝试解决“近距离”投票问题。
例如,我可以实施bool distance_at_least(begin, end, 3)
和 bool distance_at_most(begin, end, 2)
和 bool count_at_least(begin, end, val, 5)
等。
我要求使用单一(通用)方法,可以用于所有这些类型的查询。
编辑:以下是一个变体解决方案的模型,它试图说明为什么我不想写很多变种。
#include <vector>
#include <list>
namespace DETAIL {
template <class ITER, class CAT>
bool distance_at_least_dispatch(ITER begin, ITER end, typename std::iterator_traits<ITER>::difference_type n, CAT)
{
while (begin != end && n > 0) {
++begin;
--n;
}
return n == 0;
}
template <class ITER>
bool distance_at_least_dispatch(ITER begin, ITER end, typename std::iterator_traits<ITER>::difference_type n, std::random_access_iterator_tag)
{
return std::distance(begin, end) >= n;
}
}
template <class ITER>
bool distance_at_least(ITER begin, ITER end, typename std::iterator_traits<ITER>::difference_type n)
{
using CAT = typename std::iterator_traits<ITER>::iterator_category;
return DETAIL::distance_at_least_dispatch(begin, end, n, CAT());
}
int main(int argv, char* argc[])
{
std::vector<int> v;
std::list<int> l;
std::generate_n(std::back_inserter(v), 5, std::rand);
std::generate_n(std::back_inserter(l), 5, std::rand);
std::cout << distance_at_least(v.begin(), v.end(), 3) << std::endl;
std::cout << distance_at_least(v.begin(), v.end(), 5) << std::endl;
std::cout << distance_at_least(v.begin(), v.end(), 6) << std::endl;
std::cout << distance_at_least(l.begin(), l.end(), 3) << std::endl;
std::cout << distance_at_least(l.begin(), l.end(), 5) << std::endl;
std::cout << distance_at_least(l.begin(), l.end(), 6) << std::endl;
return 0;
}
答案 0 :(得分:0)
我认为这里的主要问题应该是std::count(b,e,v) < 2
对于体面的编译器是否那么糟糕。它是一个模板函数,因此在调用时可以使用完整的实现,这是一个相当简单的函数。这使其成为内联的主要候选者。这意味着优化器将看到计数返回值与<2
进行比较,然后是分支。还可以看出,计数一次增加1,并且没有副作用。
因此,可以重新调整代码,移动分支,并消除循环的冗余部分。
在伪代码中,未经优化:
count = 0
:loop
if (*b==v) ++count
++b
if(b!=e) goto loop
if(count >=2) goto past_if
// Then-block
:past_if
现在已经过优化
count = 0
:loop
if (*b==v) ++count
if(count>=2) goto past_if
++b
if(b!=e) goto loop
// Then-block
:past_if
如您所见,这是一个简单的重新排序。只有一条线移动。这不是火箭科学,一个不错的优化者应该能够解决这个问题。