我有以下枚举声明,我想在Qt中使用QFlags支持以获得额外的类型安全性:
namespace ssp
{
enum VisualAttribute
{
AttrBrushColor = 0x001,
AttrBrushTexture = 0x002,
AttrPenCapStyle = 0x004,
AttrPenColor = 0x008,
AttrPenJoinStyle = 0x010,
AttrPenPattern = 0x020,
AttrPenScalable = 0x040,
AttrPenWidth = 0x080,
AttrSymbolColor = 0x100,
AttrTextColor = 0x200,
AttrTextFontFamily = 0x400,
AttrTextHeight = 0x800,
AttrAllFlags = 0xfff
};
Q_DECLARE_FLAGS (VisualAttributes, VisualAttribute)
Q_DECLARE_OPERATORS_FOR_FLAGS (VisualAttributes)
}
此声明适用于我声明VisualAttributes参数并传递OR的值列表的方法,因此该部分很好,但它(显然)在使用其他标志(如Qt :: WindowFlags)的任何地方中断(显然)。我得到的编译错误是:
error C2664: 'void QWidget::setWindowFlags(Qt::WindowFlags)' : cannot convert argument 1 from 'int' to 'Qt::WindowFlags'
No constructor could take the source type, or constructor overload resolution was ambiguous
问题似乎与Q_DECLARE_OPERATORS_FOR_FLAGS声明有关;如果我删除它,解决了其他标志类型的编译问题,但由于这声明了标志的运算符,编译器将不接受OR'd列表。包含声明会产生某种模棱两可的定义,但我不明白它是什么。
QFlags文档显示了将枚举嵌入到类声明中的示例,这不仅看起来很麻烦,而且比我已经处理的更糟糕。我还查看了Qt的标志声明(对于Qt :: AlignmentFlag),我没有看到他们在上面的代码段中做了不同的事情。
答案 0 :(得分:2)
我能够通过将Q_DECLARE_OPERATORS_FOR_FLAGS声明移出命名空间块来解决此问题,因此它变为:
Q_DECLARE_OPERATORS_FOR_FLAGS (ssp::VisualAttributes)
这解决了所有编译问题。
答案 1 :(得分:2)
这实际上是一个(非常古老的)Qt错误。通常,由于argument dependent lookup,自定义运算符应在与其参数相同的命名空间中声明。当Qt首次引入这些标志枚举和运算符时,他们选择在全局名称空间中声明它们,可能是由于当时编译器对名称空间或依赖于参数的查找支持不佳。据推测,移动它们会破坏一些现有代码,因此它们会留在原处。 (也许这是Qt 6的考虑因素?)
因此,如果一个人是一个良好的,现代的C ++公民,并且在与其参数相同的名称空间中声明其自定义operator|
,则在同一名称空间中编译代码时,查找将找不到Qt operator|
。它在当前名称空间中找到不匹配的operator|
,并且通过依赖于参数的查找找不到operator|
。由于我无法解释的复杂原因,查找然后停止,而不是搜索将找到Qt的operator|
的全局名称空间。
因此,您有两种选择:
using ::operator|;
,以使Qt枚举运算符得以编译。