[英]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
類模板的特定實例。
func()
和FOOBAZ
兩個版本FOOBAZ
可用 當編譯器遇到對func(Test::FOOBAZ)
的調用時,它將采用FOOBAZ
的類型,並嘗試將其與函數重載進行匹配。 有兩種功能。
FOOBAZ
的類型為SimpleFlag
,它是一個枚舉。 SimpleFlag
隱式轉換為int
,后者可以轉換為bool
。 由於QFlags
具有轉換構造函數,因此SimpleFlag
也隱式轉換為MyFlags
。 在重載選擇期間,與使用“用戶定義的”構造函數(在QFlags
)進行的轉換相比,轉換為bool
QFlags
。
編譯器選擇func(bool)
,然后警告int
像bool
一樣被使用。
func(Test::MyFlags)
可用FOOBAZ
重載解析與以前一樣進行,除了func(bool)
不可用。 編譯器選擇func(MyFlags)
。 沒有警告,因為沒有像布爾值那樣使用整數。
func()
兩個版本均可用,但FOOBAZ
不可用 調用是func(Test::FOO | Test::BAZ)
。 FOO
和BAZ
都具有SimpleFlag
類型。 在查找要使用的func()
之前,編譯器會搜索operator|
重載。 。 根據有關Q_DECLARE_OPERATORS_FOR_FLAGS
的Qt文檔 ,宏定義了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
),部分是為了防止在枚舉器( FOO
, BAZ
等)以不希望的方式轉換為整數時出現此類問題。 不幸的是,至少在QObject
的范圍內,存在至少一個 QFlags
與范圍枚舉不兼容的問題 。
以下示例將避免選擇func
的bool
版本,但是可能需要進行一些調整或重新制作才能使其在實際環境中與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.