【问题标题】:Passing const as 'this' argument error when calling std::sort on a list of structures在结构列表上调用 std::sort 时将 const 作为“this”参数传递错误
【发布时间】:2017-11-30 14:49:46
【问题描述】:

我有一个相当大的struct,叫做Journey

typedef struct Journey
{
    /**
      * @brief The InfoText struct is a container for storing messages (short and long) that are found
      * inside a journey's <InfoTextLists/> as <InfoText/> elements
      */
    typedef struct InfoText
    {
        QString shortMsg;
        QString longMsg;

        InfoText(QString shortMsg, QString longMsg)
        {
            this->shortMsg = shortMsg;
            this->longMsg = longMsg;
        }

        bool operator ==(const InfoText &other)
        {
            return (this->shortMsg == other.shortMsg) && (this->longMsg == other.longMsg);
        }

        bool operator !=(const InfoText &other)
        {
            return !(*this == other);
        }
    } InfoText;


    QTime arrivalNextImmediateStop;             //!< Arrival time (planned). It can be found under Time inside Arr in XML reply
    QTime arrivalNextImmediateStopRelative;     //!< Arrival time (relative, @p arrivalNextImmediateStop + @p delay)

    // Departure data
    QTime departure;            //!< Departure time (planned). It can be found under Time inside Dep in XML reply
    quint32 departureRelative;  //!< Departure time (relative and in minutes, @p departure + @p delay - current time)
    int delay;                  //!< Departure time delay (minutes). It can be found under Delay inside Dep in XML reply

    // Transfer time
    // TODO Calculate this at the beginning of the data fusion slotGetData(). It is required for the display of the connection (remaining time column)
    QTime transferTime;         //!< Transfer time based on the CSV L and V files. Required for the lookup filter (see @ref Data::Filtering::FilterFutureLookup)

    // Direction and destination data
    quint8 direction;           //!< Run direction (1, 2). It can be found under Attribute of type DIRECTIONFLAG in XML reply
    QString directionTarget;    //!< Run direction final destination. It can be found under Attribute of type DIRECTION in XML reply

    QString operatorJ;          //!< Full name of operator of the journey (Berliener Verkehrsbetriebe, DB Regio AG ...). It can be found under Attribute of type OPERATOR in XML reply
    QString vehicleType;        //!< Type of the vehicle (B, F, U, S ...). It can be found under Attribute with of type CATEGORY in XML reply
    QString line;               //!< The line of the vehicle (for example: 109 (for Bus 109), S5 (for S-Bahn 5) etc.). It can be found under Attribute of type NUMBER in XML reply

    // Immedidate stops data
    quint32 immediateStop1;     //!< First immediate stop ID (without offset) after current station
    quint32 immediateStop2;     //!< Second immediate stop ID (without offset) after current stations

    bool dirty;                 //!< Used by the secondary filtering mechanism this value shows whether the given connection has been marked for removal or not

    /**
     * @brief Stores all <InfoText/> element found inside the journey's <InfoTextLists/> element. An info text is a message consisting of a headline (short message)
     *        and a body (long message)
     */
    QList<InfoText> infoTexts;


    /**
     * @brief Constructor
     */
    Journey()
    {
        this->arrivalNextImmediateStop = QTime();
        this->arrivalNextImmediateStop = QTime();
        this->departure = QTime();
        this->departureRelative = 0;
        this->transferTime = QTime();
        this->delay = this->direction = this->immediateStop1 = this->immediateStop2 = 0;
        this->directionTarget = this->operatorJ = this->vehicleType = this->line = "";
        this->dirty = false;
    }

    /**
     * @brief Allows comparing for equality between two journeys
     * @param other Journey to compare with
     * @return True if arrival time to both next two immediate stops, departure time, relative departure
     *         time, delay, direction, destination, journey operator, vehicle type, line and IDs of next
     *         two immediate stops are equal
     */
    bool operator ==(const Journey &other)
    {
        return arrivalNextImmediateStop == other.arrivalNextImmediateStop
                && arrivalNextImmediateStopRelative == other.arrivalNextImmediateStopRelative
                && departure == other.departure
                && departureRelative == other.departureRelative
                && delay == other.delay
                && direction == other.direction
                && directionTarget == other.directionTarget
                && operatorJ == other.operatorJ
                && vehicleType == other.vehicleType
                && line == other.line
                && immediateStop1 == other.immediateStop1
                && immediateStop2 == other.immediateStop2;
    }

    /**
     * @brief Allows comparing for inequality between two journeys
     * @param other
     * @return True if arrival time to both next two immediate stops, departure time, relative departure
     *         time, delay, direction, destination, journey operator, vehicle type, line and IDs of next
     *         two immediate stops are not equal
     */
    bool operator !=(const Journey &other)
    {
        return !(*this == other);
    }

    /**
     * @brief Overloads the < operator to allow sorting journeys in a ascending order based on their line. Due to the alphanumeric nature of
     *        most lines special handling is required to ensure proper order. With the default string comparison namely own_line < other_line the result
     *        is in most cases not correct: M10, M5, M8 instead of M5, M8, M10. Using @ref alphanumericLineSplitRx an attempt is made to split the line
     *        into two distrinctive tokens - alphabetic and numeric. If the split does not succeed the line is made only of letter or digits in which case
     *        standard string comparison can be used. On the other hand if it does succeed, we need to do a comparison of each of the two tokens. In some
     *        cases lines can be the same in which case the direction of both is used for the comparison
     * @param other A journey with a line
     * @return True if line of journey is smaller (string comparison or numeric comparison if lines are of alphanumeric or only numeric nature) than line of @p journey
     */
    bool operator < (const Journey &other)
    {
        QRegularExpressionMatch matchesOwn = alphanumericLineSplitRx.match(this->line);
        QRegularExpressionMatch matchesOther = alphanumericLineSplitRx.match(other.line);

        // Figure out if the lines of our own and the other journey are complex (alphanumeric) or simple (just alphabetic or just numeric)
        // If we have alphanumeric lines we need to split each line into two tokens - alphabetic and numeric
        if (matchesOwn.capturedTexts().length() == 3 && matchesOther.capturedTexts().length() == 3)
        {
            QString lineAlphaOwn = matchesOwn.captured(1);
            QString lineAlphaOther = matchesOther.captured(1);
            quint16 lineNumericOwn = matchesOwn.captured(2).toUInt();
            quint16 lineNumericOther = matchesOther.captured(2).toUInt();

            // If the alphabetic token of both journies are different there is not need to compare the numeric token and
            // standard string comparison is used
            // Example: N20, M100 will be sorted as M100, N20 since M comes before N
            if (lineAlphaOwn != lineAlphaOther)
            {
                return this->line < other.line;
            }

            // If the alphabetic token is the same for both lines the numeric token is the next criterion for sorting
            // Example: N10, N1, N2, N20 will be sorted as N1, N2, N10, N20
            if (lineNumericOwn != lineNumericOther)
            {
                return lineNumericOwn < lineNumericOther;
            }

            // If both the alphabetic and the numeric tokens are the same the direction will be used as the sorting criterion
            // Example: N10 (direction 2), N10 (direction 1) will be sorted as N10 (direction 1), N10 (direction 2)
            return this->direction < other.direction;
        }

        // In case the matching has failed this means that the line consists either of just a single alphabetic or numeric
        // The numeric-only case needs to be handled to avoid sorting results like 1, 100, 1000, 2, 20, 2000 ...
        bool isOwnNumericOnly = false;
        bool isOtherNumericOnly = false;
        quint16 lineNumericOwn = matchesOwn.captured(1).toUInt(&isOwnNumericOnly);
        quint16 lineNumericOther = matchesOther.captured(1).toUInt(&isOtherNumericOnly);

        if (isOwnNumericOnly && isOtherNumericOnly)
        {
            // In case the line (digits only!) of both journies are different, we use standard numeric comparison
            // Example: 206, 815, 413 will be sorted as 206, 413, 815
            if (lineNumericOwn != lineNumericOther)
            {
                return lineNumericOwn < lineNumericOther;
            }

            // Both journies have the same number for a line so the direction is used as the sorting criterion
            // Example: 280 (direction 2), 280 (direction 1) will be sorted as 280 (direction 1), 280 (direction 2)
            return this->direction < other.direction;
        }
        else
        {
            // In case the line (letters only!) of both journies are different, we use standard string comparison
            // Example: S, TXL, R will be sorted as R, S, TXL
            if (this->line != other.line)
            {
                return this->line < other.line;
            }

            // Both journies have the same letter for a line so the direction is used as the sorting criterion
            // Example: TXL (direction 2), TXL (direction 1) will be sorted as TXL (direction 1), TXL (direction 2)
            return this->direction < other.direction;
        }
    }

    /**
     * @brief Overloads the > operator to allow sorting journeys in a ascending order based on their line. Internally the overloaded
     * @ref operator < and @ref operator != operators are used
     * @param other A journey with a line
     * @return True if line of journey is greater (string comparison or numeric comparison if lines are of alphanumeric or only numeric nature) than line of @p journey
     */
    bool operator > (const Journey &other)
    {
        return (*this != other) && (*this < other);
    }

    /**
     * @brief Checks if the journey belongs to a specific vehicle type
     * @param vehicleType Type of vehicle to check own affiliation with
     * @return True if journey belongs to @p vehicleType
     */
    bool belongsToVehicleType(QString vehicleType)
    {
        return this->vehicleType == vehicleType;
    }
} Journey;

它存储从服务器的 HTTP GET 回复中检索到的数据,该服务器提供有关各种车辆及其穿过城市的路线的信息。

我正在使用的规范中的一项要求在我过滤了一次无效(基于各种标准)导致庞大的重载 &lt; 运算符(其他是这里不重要)你在上面的代码 sn-p 中看到。

我不得不将所有可用的旅程分成更小的组(基于车辆类型,这就是 belongsToVehicleType() 函数的用途)。对于每组旅程,我必须运行 std::sort 以实现所需的数据顺序。

长话短说 - 一切都在我的本地机器上运行(带有 Qt 5.4.2 的 32 位 Ubuntu 16.04)但是当我尝试交叉编译它时(目标系统也使用 Qt 5.4.2、基于 Intel 的 32 位架构等.)。请注意,如果我注释掉我调用 std::sort() 的所有行,我的代码即使使用交叉编译器也能正常编译(尽管链接器抱怨由于某种原因无法找到 libc.so.6 )。您可以在下面看到 Qt Creator 输出的错误消息:

/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h:2277:错误:传递'const数据::Journey' 作为 'bool Data::Journey::operator

当我在任何 QLists 上调用 std::sort 时,会出现此错误。例如:

QList<Journey> connectionsRE;

// Fill connectionsRE

if (connectionsRE.length())
{
    LOG(INFO) << "Regional train (Express) RE1-RE9 connections:";
    std::sort(connectionsRE.begin(), connectionsRE.end());  // <----------- ERROR STARTS FROM HERE!!!

    // Do something else with connectionsRE
}

在项目的build文件夹中运行make时的完整编译错误是

In file included from /opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/algorithm:63:0,
                 from /opt/target-toolchain/Qt/Qt5/include/QtCore/qglobal.h:81,
                 from /opt/target-toolchain/Qt/Qt5/include/QtCore/qnamespace.h:37,
                 from /opt/target-toolchain/Qt/Qt5/include/QtCore/qobjectdefs.h:41,
                 from /opt/target-toolchain/Qt/Qt5/include/QtCore/qobject.h:40,
                 from /opt/target-toolchain/Qt/Qt5/include/QtCore/QObject:1,
                 from /home/user/Projects/project/src/datafusionhandler.h:4,
                 from /home/user/Projects/project/src/datafusionhandler.cpp:1:
/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h: In instantiation of '_RandomAccessIterator std::__unguarded_partition(_RandomAccessIterator, _RandomAccessIterator, const _Tp&) [with _RandomAccessIterator = QList<Data::Journey>::iterator; _Tp = Data::Journey]':
/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h:2315:70:   required from '_RandomAccessIterator std::__unguarded_partition_pivot(_RandomAccessIterator, _RandomAccessIterator) [with _RandomAccessIterator = QList<Data::Journey>::iterator]'
/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h:2347:54:   required from 'void std::__introsort_loop(_RandomAccessIterator, _RandomAccessIterator, _Size) [with _RandomAccessIterator = QList<Data::Journey>::iterator; _Size = int]'
/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h:5483:4:   required from 'void std::sort(_RAIter, _RAIter) [with _RAIter = QList<Data::Journey>::iterator]'
/home/user/Projects/project/src/datafusionhandler.cpp:387:61:   required from here
/opt/target-toolchain/crosstools/i686-unknown-linux-gnu/lib/gcc/i686-unknown-linux-gnu/4.7.4/../../../../i686-unknown-linux-gnu/include/c++/4.7.4/bits/stl_algo.h:2277:4: error: passing 'const Data::Journey' as 'this' argument of 'bool Data::Journey::operator<(const Data::Journey&)' discards qualifiers [-fpermissive]
compilation terminated due to -Wfatal-errors.
src/CMakeFiles/project.dir/build.make:134: recipe for target 'src/CMakeFiles/project.dir/datafusionhandler.cpp.o' failed
make[2]: *** [src/CMakeFiles/project.dir/datafusionhandler.cpp.o] Error 1
CMakeFiles/Makefile2:1018: recipe for target 'src/CMakeFiles/project.dir/all' failed
make[1]: *** [src/CMakeFiles/project.dir/all] Error 2
Makefile:94: recipe for target 'all' failed
make: *** [all] Error 2

-Wfatal-errors 设置用于为我的本地计算机和目标系统构建。也许我的 rootfs 目录(存储目标操作系统的映像)中的某些底层库太旧了?

【问题讨论】:

    标签: linux qt sorting std cross-compiling


    【解决方案1】:

    我认为您可能需要将一些运算符函数声明为 const,例如:

    bool operator > (const Journey &other) const
    {
      ...
    }
    

    【讨论】:

    • 显然它有效,因为我将您的答案标记为这样。 :P 谢谢!
    • Np。虽然我仍然不确定为什么本地构建没有出现这个问题。我需要仔细检查标志。
    猜你喜欢
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2020-07-11
    • 2020-02-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多