3

Basically we're keeping the track of object types in a variable of QVariant::Type and then doing something like that

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;
}

The problem is: gcc produces warnings along these lines for User+X statements:

 warning: case value ‘1025’ not in enumerated type ‘QVariant::Type’ [-Wswitch]

Now, I could suppress that of course, but is that the recommended way or am I doing something fundamentally wrong here?

P.S. The question isn't about why the warning is produced: I understand why. The queston is more about using QVariant::Type with user types in a proper way and if simply suppressing is correct or what am I doing here is just plain wrong and warning is an indication of a bigger design decision problem.

Zeks
  • 2,265
  • 20
  • 32

2 Answers2

3

If you are going to use user types in the QVariant, you should use the member function userType:

Unfortunately, this will make things uglier:

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;
}

To clarify: Note that the type() member function will always return QVariant::UserType when the type value is greater than QMetaType::User. This means it will never return QVariant::UserType+n! How could it? Those values are not part of the enumeration.

This is what gcc is warning you about:

warning: case value ‘1025’ not in enumerated type ‘QVariant::Type’ [-Wswitch]

Since 1025(QVariant::User+1) is not part of QVariant::Type, this case label is essentially dead code.

The userType member function, however, returns int. It will return the same underlying value as type when that value is below QMetaType::User, and also the correct user value when above.

Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55
  • values[i] is not a QVariant. The type is explicitly stored outside. I am starting to suspect I need to use an external enum for that that is not a Qt enum. – Zeks Apr 27 '18 at 14:56
  • 1
    @Zeks If you are storing values outside of the range of the enum in a data member, the behavior is unspecified (prior to C++17) or **undefined** (After C++17). This means your case labels are subject to being optimized away (or worse). As you already realized, to solve this, you either: Use the underlying type instead; or, use a separate enum with all the values you need defined. – Not a real meerkat Apr 27 '18 at 15:02
  • (More info about this [here](https://stackoverflow.com/a/18195408/3854787)) – Not a real meerkat Apr 27 '18 at 15:04
  • Thanks. I seem to need to refactor that part before its too late. – Zeks Apr 27 '18 at 15:06
2

From QVariant::type enum:

QMetaType::User 1024    Base value for user types

this is like:

switch(1024) {
   ...
   case (1024 + 1): break;
   default: break;
}

the governing rule in switch for enum is to be explicit.

(1024 + 1) is not explicit thus the warning.

UPDATE

As per qvariant.html#type

Returns the storage type of the value stored in the variant. Although this function is declared as returning QVariant::Type, the return value should be interpreted as QMetaType::Type. In particular, QVariant::UserType is returned here only if the value is equal or greater than QMetaType::User.

Thus, QVariant::UserType + 1 will be dead code.

Time to refactor

Joseph D.
  • 11,804
  • 3
  • 34
  • 67
  • Wait what? First of all: where did switch(1024) come from? your answer doesnt make any sense to me – Zeks Apr 27 '18 at 13:45
  • I think the point is that each enumerator is just a name for a number in an `int` (or other underlying type). And Qt never declared any enumerator for `User + 1` (for obvious reasons), but the compiler doesn't know this is OK. I don't see that translating the code to use `int`s really helps though. – underscore_d Apr 27 '18 at 13:48
  • Your answer would make sense if there was not default: break; but it is there so by your logic, there is a conditional branch for every possible case – Zeks Apr 27 '18 at 13:53
  • Anyway, your answer deals with why the warnign is emitted, please read the P.S. of the question for what the real question is here. – Zeks Apr 27 '18 at 14:02
  • 1
    @Zeks, updated my answer. also to make things simpler, `UserType + 1` will be dead code. The warning is there since `UserType + 1` is **not** explicit. It's not part of the `enum`. compiler knows the type of `values[i].type`. – Joseph D. Apr 27 '18 at 14:10
  • I am sorry to report that you are completely wrong. I just ran a debug on that code and QVariant::User+1 branch is entered correctly. It is most certainly not a dead branch. This code has been working for a couple years and if there was a problem with dead branches it would have been noticed. And actual real life debug proved it is alive – Zeks Apr 27 '18 at 14:46
  • @Zeks, then you should be worried. you're not following the standards. – Joseph D. Apr 27 '18 at 14:53
  • @Zeks, Also the probable cause would be `User + 1` is a "special" case for your code. – Joseph D. Apr 27 '18 at 14:58
  • I don't understand what you mean by special case – Zeks Apr 27 '18 at 15:00
  • @Zeks, it means "how on earth does the program get 1025 if QT doesn't support that value for `types`" – Joseph D. Apr 27 '18 at 15:01
  • Possibly. Seems like my hunch was correct and the whole using QVariant::Type needs to go away, not the warning. Been ignoring it for way too long. – Zeks Apr 27 '18 at 15:05
  • @Zeks, [refactor now before it's too late](https://towardsdatascience.com/refactoring-is-the-cure-for-technical-debt-but-only-if-you-take-it-9fd8cc42dd93) – Joseph D. Apr 27 '18 at 15:06
  • 1
    Agreed. Once the current deadline passes here, I am refactoring this part into something sensible. – Zeks Apr 27 '18 at 15:07
  • Reporting in: refactoring this stuff did, indeed, break it in a major way :) Thankfully I caught it before it went to production. But I was right to be reluctant – Zeks Jul 26 '18 at 16:50