簡體   English   中英

為什么方法重載或枚舉標志定義會觸發gcc7.2編譯器警告?

[英]Why does a method overload or enum flag definition trigger gcc7.2 compiler warning?

在GCC 7.2(而不是4.4.7!)中編譯時,以下代碼生成“布爾上下文中的枚舉常量”(-Wint-in-bool-context)警告。 如果出現以下情況,警告將消失:

  • 我刪除了另一個重載( void func(bool)
  • 我刪除了枚舉FOOBAZ組合,並在函數調用( flagTest.func(Test::FOO | Test::BAZ) )中進行了按位或運算。

我的問題是:

  • 為什么這些更改之一都刪除了警告。 和/或為什么首先觸發它?
  • 除上述以外,我是否可以做一些簡單的更改來解決警告?

在我真正的問題的上下文中,我無法消除重載,並且使用了FOOBAZ等效項多次(類似於Qt :: AlignCenter )。 我已經做了很多搜索,但是如果我在SO或其他地方找到了任何相關內容,那么它的相關性就讓我無所適從。

#include <QFlags>

class Test
{
public:
   enum SimpleFlag
   {
      FOO = 1 << 0,
      BAR = 1 << 1,
      BAZ = 1 << 2,

      FOOBAZ = (FOO | BAZ)
   };
   Q_DECLARE_FLAGS(MyFlags, SimpleFlag)

   Test(){}

   void func(bool) { }
   void func(Test::MyFlags) { }
};

Q_DECLARE_OPERATORS_FOR_FLAGS(Test::MyFlags)

int main(int argc, char *argv[])
{
   Q_UNUSED(argc); Q_UNUSED(argv);

   Test flagTest;
   flagTest.func(Test::FOOBAZ);    
}

這個問題提出了一些有關重載選擇和隱式轉換的有趣問題。


首先, Q_DECLARE_FLAGS做什么的? Qt文檔開始,在這種情況下,此宏擴展為:

typedef QFlags<SimpleFlag> MyFlags;

因此, MyFlags是Qt提供的QFlags類模板的特定實例。

情況1: func()FOOBAZ兩個版本FOOBAZ可用

當編譯器遇到對func(Test::FOOBAZ)的調用時,它將采用FOOBAZ的類型,並嘗試將其與函數重載進行匹配。 有兩種功能。

FOOBAZ的類型為SimpleFlag ,它是一個枚舉。 SimpleFlag隱式轉換為int ,后者可以轉換為bool 由於QFlags具有轉換構造函數,因此SimpleFlag也隱式轉換為MyFlags 在重載選擇期間,與使用“用戶定義的”構造函數(在QFlags )進行的轉換相比,轉換為bool QFlags

編譯器選擇func(bool) ,然后警告intbool一樣被使用。

案例2:只有func(Test::MyFlags)可用FOOBAZ

重載解析與以前一樣進行,除了func(bool)不可用。 編譯器選擇func(MyFlags) 沒有警告,因為沒有像布爾值那樣使用整數。

情況3: func()兩個版本均可用,但FOOBAZ不可用

調用是func(Test::FOO | Test::BAZ) FOOBAZ都具有SimpleFlag類型。 在查找要使用的func()之前,編譯器會搜索operator|重載。 根據有關Q_DECLARE_OPERATORS_FOR_FLAGSQt文檔 ,宏定義了operator| Test::MyFlags 但是,在我的Qt 5.10.0副本中,它實際上定義了(在qflags.h中)

QFlags<Test::SimpleFlag> operator|(Test::SimpleFlag, Test::SimpleFlag);
QFlags<Test::SimpleFlag> operator|(Test::SimpleFlag, QFlags<Test::SimpleFlag>);

operator|的所有可用重載中operator| ,兩個參數均為Test::SimpleFlag參數不需要類型轉換。 編譯器選擇了這一點。

結果是QFlags<Test::SimpleFlag>類型的臨時對象,也稱為MyFlags 然后,編譯器必須根據MyFlags類型的參數選擇func()的版本。 因為不需要類型轉換,所以選擇func(MyFlags)

由於沒有在bool上下文中使用int因此不會發出警告。


怎么修

在C ++ 11中引入了范圍枚舉( enum class ),部分是為了防止在枚舉器( FOOBAZ等)以不希望的方式轉換為整數時出現此類問題。 不幸的是,至少在QObject的范圍內,存在至少一個 QFlags與范圍枚舉不兼容的問題

以下示例將避免選擇funcbool版本,但是可能需要進行一些調整或重新制作才能使其在實際環境中與Qt一起使用。 static constexpr變量在Test的類范圍內重新引入FOOBAZ作為標識符。 該示例在GCC 6.4.0上編譯(它似乎也缺少bool警告)。

#include <QFlags>

class Test
{
public:
    enum class SimpleFlag
    {
        FOO = 1 << 0,
        BAR = 1 << 1,
        BAZ = 1 << 2,

        FOOBAZ = (FOO | BAZ)
    };
    Q_DECLARE_FLAGS(MyFlags, SimpleFlag)

    static constexpr SimpleFlag FOOBAZ = SimpleFlag::FOOBAZ;
    Test(){}

    void func(bool) { }
    void func(Test::MyFlags) { }
};

Q_DECLARE_OPERATORS_FOR_FLAGS(Test::MyFlags)

int main(int argc, char *argv[])
{
    Q_UNUSED(argc); Q_UNUSED(argv);

    Test flagTest;
    flagTest.func(Test::FOOBAZ);    
}

這些有關重載解析隱式轉換的文章有助於准備此答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM