如何修复无效比较器错误?

问题描述

MSVS 16.9.3

Win7-64

我在第二次执行传递给 <algorithm> 中提供的 C++ Sort 函数的排序比较器时收到无效比较器错误。我不明白为什么我会收到这个错误!排序例程调用是:

sort(sorted.begin(),sorted.end(),remsort);

sorted 的定义如下:

vector<ADI::RDA_Asset*>& sorted = *(new vector<ADI::RDA_Asset*>);

这是我使用的 remsort 的三个版本:

版本 1:始终有效:

bool HOAReports::remsort(ADI::RDA_Asset* lhs,ADI::RDA_Asset* rhs) { 
   return (lhs->getRem() < rhs->getRem());
};

版本 2:适用于排序例程对 remsort 的第一次调用,在第二次调用时失败:

bool HOAReports::remsort(ADI::RDA_Asset* lhs,ADI::RDA_Asset* rhs) { 
   return (  (lhs->getRem() < rhs->getRem())
          || ((lhs->getCatName()).compare(rhs->getCatName()) < 0)
          || ((lhs->getRDAName()).compare(rhs->getRDAName()) < 0)
          };

版本 3:适用于排序例程对 remsort 的第一次调用,在第二次调用时失败:

bool HOAReports::remsort(ADI::RDA_Asset* lhs,ADI::RDA_Asset* rhs) {
   bool return_value = (  (lhs->getRem() < rhs->getRem())
                      || ((lhs->getCatName()).compare(rhs->getCatName()) < 0)
                      || ((lhs->getRDAName()).compare(rhs->getRDAName()) < 0)
                       ); 
   return return_value;
};

版本 2/3 具有相同的功能。在第一次和第二次调用 remsort 时只执行 ((lhs->getRem() < rhs->getRem()) 并且 return_value 为真。查看失败的断言,似乎在两次调用中都检查了断言,但在第二次调用中失败了。

失败的 MSVS 代码是:

// FUNCTION TEMPLATE _Debug_lt_pred
template <class _Pr,class _Ty1,class _Ty2,enable_if_t<is_same_v<_Remove_cvref_t<_Ty1>,_Remove_cvref_t<_Ty2>>,int> = 0>
constexpr bool _Debug_lt_pred(_Pr&& _Pred,_Ty1&& _Left,_Ty2&& _Right) noexcept(
    noexcept(_Pred(_Left,_Right)) && noexcept(_Pred(_Right,_Left))) {
    // test if _Pred(_Left,_Right) and _Pred is strict weak ordering,when the arguments are the cv-same-type
    const auto _Result = static_cast<bool>(_Pred(_Left,_Right));
    if (_Result) {
        _STL_VERIFY(!_Pred(_Right,_Left),"invalid comparator");
    }

    return _Result;
}

解决方法

您的比较函数不满足严格弱排序要求。见C++ named requirements: Compare

在您的具体情况下,您可以这样实现:

bool HOAReports::remsort(ADI::RDA_Asset* lhs,ADI::RDA_Asset* rhs) {
    if(lhs->getRem() < rhs->getRem()) return true;
    if(rhs->getRem() < lhs->getRem()) return false;

    // if we get here,lhs.getRem() == rhs.getRem()

    auto cmp = lhs->getCatName().compare(rhs->getCatName());
    if(cmp) return cmp < 0;

    // if we get here,lhs->getCatName() == rhs->getCatName()

    return lhs->getRDAName() < rhs->getRDAName();
}

Demo

或者更简单,使用 std::tuplestd::tie

#include <tuple>

bool HOAReports::remsort(ADI::RDA_Asset* lhs,ADI::RDA_Asset* rhs) {
    return
        std::tuple{lhs->getRem(),lhs->getCatName(),lhs->getRDAName()}
        <
        std::tuple{rhs->getRem(),rhs->getCatName(),rhs->getRDAName()};
}