什么是条件比较的优雅解决方案?

时间:2016-12-29 08:38:09

标签: c++

我想根据flag的值以desend / ascend顺序对数字向量进行排序。像这样:

int main()
{
    vector<int> numbers;
    bool is_negatif = false;
    // Do some stuff
    sort(numbers.begin(), numbers.end(), is_negatif ? less<int>(): greater<int>());
}

不幸的是,由于不同类型的less / greaters结构,这些代码不会被编译。

我正在使用这样的代码:

template<class _Ty>
struct MyComparator
{
   template <bool Less>
   static bool compare(const _Ty& _Left, const _Ty& _Right);

   template <>
   static bool compare<true>(const _Ty& _Left, const _Ty& _Right)
   {
      return _Left < _Right;
   }

   template <>
   static bool compare<false>(const _Ty& _Left, const _Ty& _Right)
   {
       return _Left > _Right;
   }
};

这是用法:

sort(numbers.begin(), numbers.end(), is_negatif ? &MyComparator<int>::compare<true> : &MyComparator<int>::compare<false>);

这种问题的优雅解决方案是什么?

注意:编译时不知道bool值!

6 个答案:

答案 0 :(得分:3)

如果您关心效果,那么拨打std::sort的单个电话不会将其删除。我刚刚检查了godbolt.org以确定:GCC和Clang都生成了将函数指针加载到寄存器中的程序集,然后将其用于std::sort中的每个比较。
由于类型擦除,std::function更糟糕。

movl    bool compareLess<int>(int const&, int const&), %ebp
// ...
movl    bool compareGreater<int>(int const&, int const&), %eax
// ...
call   [std::__introsort_loop specialized for bool (*)(int const&, int const&)]

但是,如果您将std::sort的两个专精分开:

if(is_negatif)
    sort(numbers.begin(), numbers.end(), std::less<>{});
else
    sort(numbers.begin(), numbers.end(), std::greater<>{});

最终会有两个类型感知调用,然后编译器可以内联比较。

call   [std::__introsort_loop specialized for std::less<void>]
// ...
call   [std::__introsort_loop specialized for std::greater<void>]

(为清晰起见,缩写为疯狂长专精名称)

答案 1 :(得分:2)

我找到了另一个解决方案。它似乎适合我。当然,也许有更优雅的解决方案

bool is_negatif = false;
// Do some stuff

std::function<bool(int, int)> func = less<int>();
if (!is_negatif)
    func = greater<int>();
sort(numbers.begin(), numbers.end(), func);

答案 2 :(得分:2)

您可以尝试使用以下内容:

sort(numbers.begin(), numbers.end(), 
     is_negatif ? function<bool(int,int)>(less<int>()) :
                  greater<int>());

然而,这应该比普通的std::less<int>()比较器具有更差的性能,因为这个比较器可能不会内联。

在正文中使用is_negatif的比较器更容易内联,但它们会浪费一次又一次地检查is_negatif周期。

如果您想获得出色的表现,请保持简单:

if (is_negatif)
    sort (numbers.begin(), numbers.end(), less<int>());
else
    sort (numbers.begin(), numbers.end(), greater<int>());

答案 3 :(得分:1)

template <class T>
struct MyComparator
{
    MyComparator(bool __is_negatif)
    {
            m_is_negatif = __is_negatif;
    }
    bool operator()(const T& x, const T& y) const
    {
            if(m_is_negatif)
            {
                    return (x > y);
            }

            return (x < y);
    }
    private:
            bool m_is_negatif;
};


 vector<int> numbers;
 bool is_negatif = false;
 sort(numbers.begin(), numbers.end(), MyComparator<int>(is_negatif));

答案 4 :(得分:1)

另一种解决方案是将整个事物包裹在lambda中:

sort(numbers.begin(), numbers.end(), [&](int l, int r) {
  return is_negatif ? l < r : l > r;
});

如果您担心影响性能的条件太多,请不要这样做。任何半个体面的分支预测器都将确定在排序期间应始终调用哪个比较。

答案 5 :(得分:0)

lambda怎么样?

bool ascending = false;
auto sorting_condition = [&](const int & a, const int & b) -> bool {
    if (ascending) return a > b;
    else return !(a < b);
}

sort(numbers.begin(), numbers.end(), sorting_condition);