在 GCC 7.2(但不是 4.4.7!)中编译时,生成以下代码 “ bool 上下文中的枚举常量”(-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 documentation ,这个宏扩展为,在这种情况下:
typedef QFlags<SimpleFlag> MyFlags;
所以 MyFlags
是 QFlags
的特定实例Qt 提供的类模板。
案例 1:func()
的两个版本和 FOOBAZ
可用
当编译器遇到对 func(Test::FOOBAZ)
的调用时它采用 FOOBAZ
的类型,并尝试将其与函数重载相匹配。有两个功能可用。
FOOBAZ
的类型是SimpleFlag
,这是一个枚举。 SimpleFlag
隐式转换为 int
, 可以转换为 bool
. SimpleFlag
也隐式转换为 MyFlags
因为QFlags
有一个converting constructor .在过载选择期间,转换为 bool
优于使用“用户定义”构造函数的转换(在 QFlags
中)。
编译器选择func(bool)
, 然后警告 int
被用作 bool
.
情况2:只有func(Test::MyFlags)
可用 FOOBAZ
除func(bool)
外,过载解决方案与以前一样进行不可用。编译器选择 func(MyFlags)
.没有警告,因为没有像 bool 值那样使用整数。
案例 3:func()
的两个版本可用,但 FOOBAZ
不可用
来电是func(Test::FOO | Test::BAZ)
.两者 FOO
和 BAZ
有类型 SimpleFlag
.在查找哪个func()
之前要使用,编译器会搜索 operator|
的重载.根据Qt documentation对于 Q_DECLARE_OPERATORS_FOR_FLAGS
, 宏定义 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|
的所有可用重载中, 两个参数都是 Test::SimpleFlag
的那个不需要类型转换。编译器选择这个。
结果是一个 QFlags<Test::SimpleFlag>
类型的临时对象,也称为 MyFlags
.然后编译器必须选择一个版本 func()
基于 MyFlags
类型的参数.它选择 func(MyFlags)
因为不需要类型转换。
没有发出警告,因为 int
尚未在 bool
中使用上下文。
如何修复
作用域枚举
( enum class
) 在 C++11 中引入,部分是为了防止在枚举器 ( FOO
、 BAZ
等) 以不希望的方式转换为整数时出现此类问题。不幸的是,至少有 one problem其中 QFlags
与范围枚举不兼容,至少在 QObject
范围内.
以下示例将避免选择 bool
func
的版本, 但可能需要进行一些调整或返工才能使其在现实世界中与 Qt 一起工作。 static constexpr
变量重新引入 FOOBAZ
作为 Test
类范围内的标识符.该示例在 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);
}
overload resolution 上的这些文章和 implicit conversion对准备这个答案很有帮助。
关于c++ - 为什么方法重载或枚举标志定义会触发 gcc7.2 编译器警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49951267/