在 switch 块中使用 QVariant::Type 的用户类型的 GCC 警告
Posted
技术标签:
【中文标题】在 switch 块中使用 QVariant::Type 的用户类型的 GCC 警告【英文标题】:GCC warnings for user types using QVariant::Type in a switch block 【发布时间】:2018-04-27 12:22:03 【问题描述】:基本上,我们在 QVariant::Type 的变量中跟踪对象类型,然后做类似的事情
switch(values[i].type)
case QVariant::Bool: logic; break;
case QVariant::Int: logic; break;
case QVariant::LongLong: logic; break;
case QVariant::String: logic; break;
case QVariant::Double: logic; break;
case QVariant::DateTime:
case QVariant::Date:
case QVariant::Time: logic; break;
case QVariant::User+1:
logic;break;
case QVariant::User+2:
logic;break;
default: break;
问题是:gcc 会为 User+X 语句产生如下警告:
warning: case value ‘1025’ not in enumerated type ‘QVariant::Type’ [-Wswitch]
现在,我当然可以压制它,但这是推荐的方式还是我在这里做的根本错误?
附:问题不在于为什么会产生警告:我明白为什么。问题更多地是关于以适当的方式将 QVariant::Type 与用户类型一起使用,如果简单地抑制是正确的,或者我在这里做什么是完全错误的,并且警告表明存在更大的设计决策问题。
【问题讨论】:
也许您正在使用-Wswitch-enum
标志进行编译?
我正在使用 -Wall -Wextra 进行编译。所以,如果我想保留这些(其他相关的)警告,你建议我只是压制?
【参考方案1】:
如果你要在 QVariant 中使用用户类型,你应该使用成员函数userType:
不幸的是,这会让事情变得更丑:
auto u = [](auto& v)return static_cast<int>(v);;
switch(values[i].userType())
case u(QVariant::Bool): logic; break;
case u(QVariant::Int): logic; break;
case u(QVariant::LongLong): logic; break;
case u(QVariant::String): logic; break;
case u(QVariant::Double): logic; break;
case u(QVariant::DateTime):
case u(QVariant::Date):
case u(QVariant::Time): logic; break;
case u(QVariant::User)+1:
logic;break;
case u(QVariant::User)+2:
logic;break;
default: break;
澄清:请注意,当类型值大于QMetaType::User
时,type()
成员函数将始终返回QVariant::UserType
。这意味着它永远不会返回QVariant::UserType+n
!怎么可能?这些值不是枚举的一部分。
这就是 gcc 警告你的:
warning: case value ‘1025’ not in enumerated type ‘QVariant::Type’ [-Wswitch]
由于1025
(QVariant::User+1
) 不是QVariant::Type
的一部分,所以这个case 标签本质上是死代码。
但是,userType
成员函数返回 int
。当该值低于QMetaType::User
时,它将返回与type
相同的基础值,并且在高于type
时返回正确的用户值。
【讨论】:
values[i] 不是 QVariant。该类型显式存储在外部。我开始怀疑我需要使用不是 Qt 枚举的外部枚举。 @Zeks 如果您在数据成员中存储超出枚举范围的值,则行为未指定(C++17 之前)或 undefined(之后C++17)。这意味着您的案例标签可能会被优化掉(或更糟)。正如您已经意识到的那样,要解决这个问题,您可以: 改用底层类型;或者,使用单独的枚举来定义您需要定义的所有值。 (更多信息here) 谢谢。我似乎需要在为时已晚之前重构那部分。【参考方案2】:来自QVariant::type enum
:
QMetaType::User 1024 Base value for user types
这就像:
switch(1024)
...
case (1024 + 1): break;
default: break;
enum
的切换规则是显式。
(1024 + 1)
不明确,因此发出警告。
更新
根据qvariant.html#type
返回变量中存储的值的存储类型。虽然 这个函数被声明为返回 QVariant::Type,返回 value 应该被解释为 QMetaType::Type。尤其,
QVariant::UserType
在此处返回仅当值等于或 大于 QMetaType::User。
因此,QVariant::UserType + 1
将是死代码。
到refactor的时间
【讨论】:
等等什么?首先:switch(1024) 是从哪里来的?你的回答对我没有任何意义 我认为关键是每个枚举器只是int
(或其他基础类型)中的一个数字的名称。 Qt 从未为User + 1
声明任何枚举器(原因很明显),但编译器不知道这是可以的。不过,我认为将代码翻译为使用 int
s 并没有真正的帮助。
如果没有默认值,您的答案将是有意义的:break;但根据你的逻辑,每个可能的情况都有一个条件分支
@Zeks,更新了我的答案。为了让事情更简单,UserType + 1
将是死代码。由于UserType + 1
是不明确的,因此存在警告。它不是enum
的一部分。编译器知道values[i].type
的类型。
同意。一旦当前的截止日期过去了,我将把这部分重构为合理的东西。以上是关于在 switch 块中使用 QVariant::Type 的用户类型的 GCC 警告的主要内容,如果未能解决你的问题,请参考以下文章