error: invalid operands of types 'bool' and 'int' to binary 'operator<=> - (GCC 10 - std=gnu++20)

error: invalid operands of types 'bool' and 'int' to binary 'operator<=> - (GCC 10 - std=gnu++20)

在支持 c++20 发布后我有一些 c++ 项目,我想将我的 makefile std 支持从 17 升级到 20,在那之后我的编译器 (gcc10.2) 给我这样的错误;

Error

In file included from /usr/local/lib/gcc10/include/c++/bits/node_handle.h:39,
                 from /usr/local/lib/gcc10/include/c++/bits/stl_tree.h:72,
                 from /usr/local/lib/gcc10/include/c++/map:60,
                 from AsyncSQL.h:10,
                 from AsyncSQL.cpp:4:
/usr/local/lib/gcc10/include/c++/optional: In function 'constexpr std::strong_ordering std::operator<=>(const std::optional<_Tp>&, std::nullopt_t)':
/usr/local/lib/gcc10/include/c++/optional:1052:24: error: invalid operands of types 'bool' and 'int' to binary 'operator<=>'
 1052 |     { return bool(__x) <=> false; }
      |              ~~~~~~~~~ ^~~
      |              |
      |              bool
gmake[2]: *** [Makefile:23: AsyncSQL.o] Error 1

这是我的 AsyncSQL.cpp ;

#include <sys/time.h>
#include <cstdlib>
#include <cstring>
#include "AsyncSQL.h"
#define MUTEX_LOCK(mtx)   pthread_mutex_lock(mtx)
#define MUTEX_UNLOCK(mtx) pthread_mutex_unlock(mtx)

CAsyncSQL::CAsyncSQL(): m_stHost (""), m_stUser (""), m_stPassword (""), m_stDB (""), m_stLocale (""), m_iMsgCount (0), m_iPort (0), m_bEnd (false), m_hThread (0), m_mtxQuery (NULL), m_mtxResult (NULL), m_iQueryFinished (0), m_ulThreadID (0), m_bConnected (false), m_iCopiedQuery (0)
{
    memset (&m_hDB, 0, sizeof (m_hDB));

    m_aiPipe[0] = 0;
    m_aiPipe[1] = 0;
}

CAsyncSQL::~CAsyncSQL()
{
    Quit();
    Destroy();
}

void CAsyncSQL::Destroy()
{
    if (m_hDB.host)
    {
        sys_log (0, "AsyncSQL: closing mysql connection.");
        mysql_close (&m_hDB);
        m_hDB.host = NULL;
    }

    if (m_mtxQuery)
    {
        pthread_mutex_destroy (m_mtxQuery);
        delete m_mtxQuery;
        m_mtxQuery = NULL;
    }

    if (m_mtxResult)
    {
        pthread_mutex_destroy (m_mtxResult);
        delete m_mtxResult;
        m_mtxQuery = NULL;
    }
}

void* AsyncSQLThread (void* arg)
{
    CAsyncSQL* pSQL = ((CAsyncSQL*) arg);

    if (!pSQL->Connect())
    {
        return NULL;
    }

    pSQL->ChildLoop();
    return NULL;
}

bool CAsyncSQL::QueryLocaleSet()
{
    if (0 == m_stLocale.length())
    {
        sys_err ("m_stLocale == 0");
        return true;
    }

    if (mysql_set_character_set (&m_hDB, m_stLocale.c_str()))
    {
        sys_err ("cannot set locale %s by 'mysql_set_character_set', errno %u %s", m_stLocale.c_str(), mysql_errno (&m_hDB) , mysql_error (&m_hDB));
        return false;
    }

    sys_log (0, "\t--mysql_set_character_set(%s)", m_stLocale.c_str());

    return true;
}

bool CAsyncSQL::Connect()
{
    if (0 == mysql_init (&m_hDB))
    {
        fprintf (stderr, "mysql_init failed\n");
        return false;
    }

    if (!m_stLocale.empty())
    {
        if (mysql_options (&m_hDB, MYSQL_SET_CHARSET_NAME, m_stLocale.c_str()) != 0)
        {
            fprintf (stderr, "mysql_option failed : MYSQL_SET_CHARSET_NAME %s ", mysql_error(&m_hDB));
        }
    }

    if (!mysql_real_connect (&m_hDB, m_stHost.c_str(), m_stUser.c_str(), m_stPassword.c_str(), m_stDB.c_str(), m_iPort, NULL, CLIENT_MULTI_STATEMENTS))
    {
        fprintf (stderr, "mysql_real_connect: %s\n", mysql_error(&m_hDB));
        return false;
    }

    my_bool reconnect = true;

    if (0 != mysql_options (&m_hDB, MYSQL_OPT_RECONNECT, &reconnect))
    {
        fprintf (stderr, "mysql_option: %s\n", mysql_error(&m_hDB));
    }



    m_ulThreadID = mysql_thread_id (&m_hDB);

    m_bConnected = true;
    return true;
}

bool CAsyncSQL::Setup (CAsyncSQL* sql, bool bNoThread)
{
    return Setup (sql->m_stHost.c_str(), sql->m_stUser.c_str(), sql->m_stPassword.c_str(), sql->m_stDB.c_str(), sql->m_stLocale.c_str(), bNoThread, sql->m_iPort);
}

bool CAsyncSQL::Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread, int iPort)
{
    m_stHost = c_pszHost;
    m_stUser = c_pszUser;
    m_stPassword = c_pszPassword;
    m_stDB  = c_pszDB;
    m_iPort = iPort;

    if (c_pszLocale)
    {
        m_stLocale = c_pszLocale;
        sys_log (0, "AsyncSQL: locale %s", m_stLocale.c_str());
    }

    if (!bNoThread)
    {
        m_mtxQuery  = new pthread_mutex_t;
        m_mtxResult = new pthread_mutex_t;

        if (0 != pthread_mutex_init (m_mtxQuery, NULL))
        {
            perror ("pthread_mutex_init");
            exit (0);
        }

        if (0 != pthread_mutex_init (m_mtxResult, NULL))
        {
            perror ("pthread_mutex_init");
            exit (0);
        }

        pthread_create (&m_hThread, NULL, AsyncSQLThread, this);

        return true;
    }
    else
    {
        return Connect();
    }
}

void CAsyncSQL::Quit()
{
    m_bEnd = true;
    m_sem.Release();

    if (m_hThread)
    {
        pthread_join (m_hThread, NULL);
        m_hThread = NULL;
    }
}

SQLMsg* CAsyncSQL::DirectQuery (const char* c_pszQuery)
{
    if (m_ulThreadID != mysql_thread_id (&m_hDB))
    {
        sys_log (0, "MySQL connection was reconnected. querying locale set");
        while (!QueryLocaleSet());
        m_ulThreadID = mysql_thread_id (&m_hDB);
    }

    SQLMsg* p = new SQLMsg;

    p->m_pkSQL = &m_hDB;
    p->iID = ++m_iMsgCount;
    p->stQuery = c_pszQuery;

    if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
    {
        char buf[1024];

        snprintf (buf, sizeof(buf), "AsyncSQL::DirectQuery : mysql_query error: %s\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());

        sys_err (buf);
        p->uiSQLErrno = mysql_errno (&m_hDB);
    }

    p->Store();
    return p;
}

void CAsyncSQL::AsyncQuery (const char* c_pszQuery)
{
    auto p = new SQLMsg;

    p->m_pkSQL = &m_hDB;
    p->iID = ++m_iMsgCount;
    p->stQuery = c_pszQuery;

    PushQuery (p);
}

void CAsyncSQL::ReturnQuery (const char* c_pszQuery, void* pvUserData)
{
    auto p = new SQLMsg;

    p->m_pkSQL = &m_hDB;
    p->iID = ++m_iMsgCount;
    p->stQuery = c_pszQuery;
    p->bReturn = true;
    p->pvUserData = pvUserData;

    PushQuery (p);
}

void CAsyncSQL::PushResult (SQLMsg* p)
{
    MUTEX_LOCK (m_mtxResult);

    m_queue_result.push (p);

    MUTEX_UNLOCK (m_mtxResult);
}

bool CAsyncSQL::PopResult(SQLMsg** pp)
{
    MUTEX_LOCK (m_mtxResult);

    if (m_queue_result.empty())
    {
        MUTEX_UNLOCK (m_mtxResult);
        return false;
    }

    *pp = m_queue_result.front();
    m_queue_result.pop();
    MUTEX_UNLOCK (m_mtxResult);
    return true;
}

void CAsyncSQL::PushQuery (SQLMsg* p)
{
    MUTEX_LOCK (m_mtxQuery);

    m_queue_query.push (p);
    m_sem.Release();

    MUTEX_UNLOCK (m_mtxQuery);
}

bool CAsyncSQL::PeekQuery (SQLMsg** pp)
{
    MUTEX_LOCK (m_mtxQuery);

    if (m_queue_query.empty())
    {
        MUTEX_UNLOCK (m_mtxQuery);
        return false;
    }

    *pp = m_queue_query.front();
    MUTEX_UNLOCK (m_mtxQuery);
    return true;
}

bool CAsyncSQL::PopQuery (int iID)
{
    MUTEX_LOCK (m_mtxQuery);

    if (m_queue_query.empty())
    {
        MUTEX_UNLOCK (m_mtxQuery);
        return false;
    }

    m_queue_query.pop();
    MUTEX_UNLOCK (m_mtxQuery);
    return true;
}

bool CAsyncSQL::PeekQueryFromCopyQueue (SQLMsg** pp)
{
    if (m_queue_query_copy.empty())
    {
        return false;
    }

    *pp = m_queue_query_copy.front();
    return true;
}

int CAsyncSQL::CopyQuery()
{
    MUTEX_LOCK (m_mtxQuery);

    if (m_queue_query.empty())
    {
        MUTEX_UNLOCK (m_mtxQuery);
        return -1;
    }

    while (!m_queue_query.empty())
    {
        SQLMsg* p = m_queue_query.front();
        m_queue_query_copy.push (p);
        m_queue_query.pop();
    }
    int count = m_queue_query_copy.size();

    MUTEX_UNLOCK (m_mtxQuery);
    return count;
}

bool CAsyncSQL::PopQueryFromCopyQueue()
{
    if (m_queue_query_copy.empty())
    {
        return false;
    }

    m_queue_query_copy.pop();
    return true;
}

int CAsyncSQL::GetCopiedQueryCount()
{
    return m_iCopiedQuery;
}

void CAsyncSQL::ResetCopiedQueryCount()
{
    m_iCopiedQuery = 0;
}

void CAsyncSQL::AddCopiedQueryCount (int iCopiedQuery)
{
    m_iCopiedQuery += iCopiedQuery;
}

DWORD CAsyncSQL::CountQuery()
{
    return m_queue_query.size();
}

DWORD CAsyncSQL::CountResult()
{
    return m_queue_result.size();
}

void __timediff (struct timeval* a, struct timeval* b, struct timeval* rslt)
{
    if (a->tv_sec < b->tv_sec)
    {
        rslt->tv_sec = rslt->tv_usec = 0;
    }
    else if (a->tv_sec == b->tv_sec)
    {
        if (a->tv_usec < b->tv_usec)
        {
            rslt->tv_sec = rslt->tv_usec = 0;
        }
        else
        {
            rslt->tv_sec = 0;
            rslt->tv_usec = a->tv_usec - b->tv_usec;
        }
    }
    else
    {
        rslt->tv_sec = a->tv_sec - b->tv_sec;

        if (a->tv_usec < b->tv_usec)
        {
            rslt->tv_usec = a->tv_usec + 1000000 - b->tv_usec;
            rslt->tv_sec--;
        }
        else
        {
            rslt->tv_usec = a->tv_usec - b->tv_usec;
        }
    }
}

class cProfiler
{
public:
    cProfiler()
    {
        m_nInterval = 0 ;

        memset (&prev, 0, sizeof (prev));
        memset (&now,  0, sizeof (now));
        memset (&interval, 0, sizeof (interval));

        Start();
    }

    cProfiler (int nInterval = 100000)
    {
        m_nInterval = nInterval;

        memset (&prev, 0, sizeof (prev));
        memset (&now,  0, sizeof (now));
        memset (&interval, 0, sizeof (interval));

        Start();
    }

    void Start()
    {
        gettimeofday (&prev , (struct timezone*) 0);
    }

    void Stop()
    {
        gettimeofday (&now, (struct timezone*) 0); 
        __timediff (&now, &prev, &interval);
    }

    bool IsOk()
    {
        if (interval.tv_sec > (m_nInterval / 1000000))
        {
            return false;
        }

        if (interval.tv_usec > m_nInterval)
        {
            return false;
        }

        return true;
    }

    struct timeval* GetResult()
    {
        return &interval;
    }
    long GetResultSec()
    {
        return interval.tv_sec;
    }
    long GetResultUSec()
    {
        return interval.tv_usec;
    }

private:
    int m_nInterval;
    struct timeval prev;
    struct timeval now;
    struct timeval interval;
};

void CAsyncSQL::ChildLoop()
{
    cProfiler profiler(500000);

    while (!m_bEnd)
    {
        m_sem.Wait();

        int count = CopyQuery();

        if (count <= 0)
        {
            continue;
        }

        AddCopiedQueryCount (count);

        SQLMsg* p;

        while (count--)
        {
            profiler.Start();

            if (!PeekQueryFromCopyQueue (&p))
            {
                continue;
            }

            if (m_ulThreadID != mysql_thread_id (&m_hDB))
            {
                sys_log (0, "MySQL connection was reconnected. querying locale set");
                while (!QueryLocaleSet());
                m_ulThreadID = mysql_thread_id (&m_hDB);
            }

            if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
            {
                p->uiSQLErrno = mysql_errno (&m_hDB);

                sys_err ("AsyncSQL: query failed: %s (query: %s errno: %d)", mysql_error (&m_hDB), p->stQuery.c_str(), p->uiSQLErrno);

                switch (p->uiSQLErrno)
                {
                    case CR_SOCKET_CREATE_ERROR:
                    case CR_CONNECTION_ERROR:
                    case CR_IPSOCK_ERROR:
                    case CR_UNKNOWN_HOST:
                    case CR_SERVER_GONE_ERROR:
                    case CR_CONN_HOST_ERROR:
                    case ER_NOT_KEYFILE:
                    case ER_CRASHED_ON_USAGE:
                    case ER_CANT_OPEN_FILE:
                    case ER_HOST_NOT_PRIVILEGED:
                    case ER_HOST_IS_BLOCKED:
                    case ER_PASSWORD_NOT_ALLOWED:
                    case ER_PASSWORD_NO_MATCH:
                    case ER_CANT_CREATE_THREAD:
                    case ER_INVALID_USE_OF_NULL:
                        m_sem.Release();
                        sys_err ("AsyncSQL: retrying");
                        continue;
                }
            }

            profiler.Stop();

            if (!profiler.IsOk())
            {
                sys_log (0, "[QUERY : LONG INTERVAL(OverSec %ld.%ld)] : %s", profiler.GetResultSec(), profiler.GetResultUSec(), p->stQuery.c_str());
            }

            PopQueryFromCopyQueue();

            if (p->bReturn)
            {
                p->Store();
                PushResult (p);
            }
            else
            {
                delete p;
            }

            ++m_iQueryFinished;
        }
    }

    SQLMsg* p;

    while (PeekQuery (&p))
    {
        if (m_ulThreadID != mysql_thread_id (&m_hDB))
        {
            sys_log (0, "MySQL connection was reconnected. querying locale set");
            while (!QueryLocaleSet());
            m_ulThreadID = mysql_thread_id (&m_hDB);
        }

        if (mysql_real_query (&m_hDB, p->stQuery.c_str(), p->stQuery.length()))
        {
            p->uiSQLErrno = mysql_errno (&m_hDB);

            sys_err ("AsyncSQL::ChildLoop : mysql_query error: %s:\nquery: %s", mysql_error (&m_hDB), p->stQuery.c_str());

            switch (p->uiSQLErrno)
            {
                case CR_SOCKET_CREATE_ERROR:
                case CR_CONNECTION_ERROR:
                case CR_IPSOCK_ERROR:
                case CR_UNKNOWN_HOST:
                case CR_SERVER_GONE_ERROR:
                case CR_CONN_HOST_ERROR:
                case ER_NOT_KEYFILE:
                case ER_CRASHED_ON_USAGE:
                case ER_CANT_OPEN_FILE:
                case ER_HOST_NOT_PRIVILEGED:
                case ER_HOST_IS_BLOCKED:
                case ER_PASSWORD_NOT_ALLOWED:
                case ER_PASSWORD_NO_MATCH:
                case ER_CANT_CREATE_THREAD:
                case ER_INVALID_USE_OF_NULL:
                    continue;
            }
        }

        sys_log (0, "QUERY_FLUSH: %s", p->stQuery.c_str());

        PopQuery (p->iID);

        if (p->bReturn)
        {
            p->Store();
            PushResult (p);
        }
        else
        {
            delete p;
        }

        ++m_iQueryFinished;
    }
}

int CAsyncSQL::CountQueryFinished()
{
    return m_iQueryFinished;
}

void CAsyncSQL::ResetQueryFinished()
{
    m_iQueryFinished = 0;
}

MYSQL* CAsyncSQL::GetSQLHandle()
{
    return &m_hDB;
}

size_t CAsyncSQL::EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize)
{
    if (0 == srcSize)
    {
        memset (dst, 0, dstSize);
        return 0;
    }

    if (0 == dstSize)
    {
        return 0;
    }

    if (dstSize < srcSize * 2 + 1)
    {
        char tmp[256];
        size_t tmpLen = sizeof (tmp) > srcSize ? srcSize : sizeof (tmp);
        strlcpy (tmp, src, tmpLen);

        sys_err ("FATAL ERROR!! not enough buffer size (dstSize %u srcSize %u src%s: %s)", dstSize, srcSize, tmpLen != srcSize ? "(trimmed to 255 characters)" : "", tmp);

        dst[0] = '[=11=]';
        return 0;
    }

    return mysql_real_escape_string (GetSQLHandle(), dst, src, srcSize);
}

void CAsyncSQL2::SetLocale (const std::string & stLocale)
{
    m_stLocale = stLocale;
    QueryLocaleSet();
}

这是我的AsyncSQL.h

#ifndef __INC_METIN_II_ASYNCSQL_H__
#define __INC_METIN_II_ASYNCSQL_H__

#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "Semaphore.h"

typedef struct _SQLResult
{
    _SQLResult(): pSQLResult (NULL), uiNumRows (0), uiAffectedRows (0), uiInsertID (0) {}

    ~_SQLResult()
    {
        if (pSQLResult)
        {
            mysql_free_result (pSQLResult);
            pSQLResult = NULL;
        }
    }

    MYSQL_RES* pSQLResult;
    uint32_t uiNumRows;
    uint32_t uiAffectedRows;
    uint32_t uiInsertID;
} SQLResult;

typedef struct _SQLMsg
{
    _SQLMsg() : m_pkSQL (NULL), iID (0), uiResultPos (0), pvUserData (NULL), bReturn (false), uiSQLErrno (0) {}

    ~_SQLMsg()
    {
        auto first = vec_pkResult.begin();
        auto past  = vec_pkResult.end();

        while (first != past)
        {
            delete * (first++);
        }

        vec_pkResult.clear();
    }

    void Store()
    {
        do
        {
            SQLResult* pRes = new SQLResult;

            pRes->pSQLResult = mysql_store_result (m_pkSQL);
            pRes->uiInsertID = mysql_insert_id (m_pkSQL);
            pRes->uiAffectedRows = mysql_affected_rows (m_pkSQL);

            if (pRes->pSQLResult)
            {
                pRes->uiNumRows = mysql_num_rows (pRes->pSQLResult);
            }
            else
            {
                pRes->uiNumRows = 0;
            }

            vec_pkResult.push_back (pRes);
        }
        while (!mysql_next_result (m_pkSQL));
    }

    SQLResult* Get()
    {
        if (uiResultPos >= vec_pkResult.size())
        {
            return NULL;
        }

        return vec_pkResult[uiResultPos];
    }

    bool Next()
    {
        if (uiResultPos + 1 >= vec_pkResult.size())
        {
            return false;
        }

        ++uiResultPos;
        return true;
    }

    MYSQL* m_pkSQL;
    int iID;
    std::string stQuery;

    std::vector<SQLResult *> vec_pkResult;
    unsigned int uiResultPos;

    void* pvUserData;
    bool  bReturn;

    unsigned int uiSQLErrno;
} SQLMsg;

class CAsyncSQL
{
public:
    CAsyncSQL();
    virtual ~CAsyncSQL();

    void Quit();

    bool Setup (const char* c_pszHost, const char* c_pszUser, const char* c_pszPassword, const char* c_pszDB, const char* c_pszLocale, bool bNoThread = false, int iPort = 0);
    bool Setup (CAsyncSQL* sql, bool bNoThread = false);

    bool Connect();
    bool IsConnected()
    {
        return m_bConnected;
    }
    bool QueryLocaleSet();

    void AsyncQuery  (const char* c_pszQuery);
    void ReturnQuery (const char* c_pszQuery, void* pvUserData);
    SQLMsg* DirectQuery (const char* c_pszQuery);

    DWORD CountQuery();
    DWORD CountResult();

    void PushResult (SQLMsg* p);
    bool PopResult  (SQLMsg** pp);

    void ChildLoop();

    MYSQL* GetSQLHandle();

    int  CountQueryFinished();
    void ResetQueryFinished();

    size_t EscapeString (char* dst, size_t dstSize, const char* src, size_t srcSize);

protected:
    void Destroy();
    void PushQuery (SQLMsg* p);

    bool PeekQuery (SQLMsg** pp);
    bool PopQuery  (int iID);

    bool PeekQueryFromCopyQueue (SQLMsg** pp );
    INT  CopyQuery();
    bool PopQueryFromCopyQueue();

public:
    int  GetCopiedQueryCount();
    void ResetCopiedQueryCount();
    void AddCopiedQueryCount (int iCopiedQuery);

protected:
    MYSQL m_hDB;

    std::string m_stHost;
    std::string m_stUser;
    std::string m_stPassword;
    std::string m_stDB;
    std::string m_stLocale;

    int m_iMsgCount;
    int m_aiPipe[2];
    int m_iPort;

    std::queue<SQLMsg*> m_queue_query;
    std::queue<SQLMsg*> m_queue_query_copy;
    std::queue<SQLMsg*> m_queue_result;

    volatile bool m_bEnd;

    pthread_t m_hThread;
    pthread_mutex_t* m_mtxQuery;
    pthread_mutex_t* m_mtxResult;

    CSemaphore m_sem;

    int m_iQueryFinished;

    unsigned long m_ulThreadID;
    bool m_bConnected;
    int  m_iCopiedQuery;
};

class CAsyncSQL2 : public CAsyncSQL
{
public:
    void SetLocale (const std::string & stLocale);
};

#endif

这就是导致错误的函数;

可选:1052;

    #ifdef __cpp_lib_three_way_comparison
  template<typename _Tp>
    constexpr strong_ordering
    operator<=>(const optional<_Tp>& __x, nullopt_t) noexcept
    { return bool(__x) <=> false; }
#else

在看到微软发布的文档后,我将尝试 <=> false;像这样再出错..

此致。

我不知道为什么它看起来像 bool(__x) <=> false 作为 bool 和 int 比较。 我认为您之前包含的文件中包含一些奇怪的宏,以包含将破坏标准代码的 header。 我建议您尝试移动到标准 headers 之上并低于它们 'user defined' headers.

#include <string>
#include <queue>
#include <vector>
#include <map>
#include <mysql/server/mysql.h>
#include <mysql/server/errmsg.h>
#include <mysql/server/mysqld_error.h>
#include "../../libthecore/src/stdafx.h"
#include "../../libthecore/src/log.h"
#include "../../Ayarlar.h"
#include "Semaphore.h"

编辑: 我找到了问题的原因。 在“libthrecore/stdafx.h”中定义的宏(我拥有使用作者的文件,它们是 public)。

#ifndef false
#define false   0
#define true    (!false)
#endif

它导致 false 被读取为 int 并导致宇宙飞船操作员失败并出现作者显示的错误。将标准 header 上移或删除宏以解决错误。