在 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 声明任何枚举器(原因很明显),但编译器不知道这是可以的。不过,我认为将代码翻译为使用 ints 并没有真正的帮助。 如果没有默认值,您的答案将是有意义的:break;但根据你的逻辑,每个可能的情况都有一个条件分支 @Zeks,更新了我的答案。为了让事情更简单,UserType + 1 将是死代码。由于UserType + 1明确的,因此存在警告。它不是enum 的一部分。编译器知道values[i].type 的类型。 同意。一旦当前的截止日期过去了,我将把这部分重构为合理的东西。

以上是关于在 switch 块中使用 QVariant::Type 的用户类型的 GCC 警告的主要内容,如果未能解决你的问题,请参考以下文章

switch case的用法

c语言 switch的用法

switch语句的用法?

switch用法

java,循环结构简洁介绍(浓缩才是精华)

java,循环结构简洁介绍(浓缩才是精华)