Enums и троичное странное поведение в gcc7 - PullRequest
1 голос
/ 04 июня 2019

Сейчас мы тестируем компиляцию некоторого кода Qt под QtCreator с более новым gcc 7.3, доступным в Ubuntu 18 (ранее мы использовали gcc 4.9.3 под Ubuntu 16).

Qt обеспечивает enum таким образом:

enum CheckState {
    Unchecked,
    PartiallyChecked,
    Checked
};

Теперь, когда мы используем троичный оператор с этим:

QVariant MyClass::MyFunc(const QModelIndex &index, int role) const {
    return (someCondition ? Qt::Checked : Qt::Unchecked);
}

затем gcc жалуется (с предупреждением, но мы рассматриваем предупреждения как ошибки):

prog.cpp:999:99:
    error: passing ‘Qt::CheckState’ chooses ‘int’
        over ‘uint {aka unsigned int}’ [-Werror=sign-promo]

Мы можем обойти проблему с:

return (someCondition ? Qt::Checked : static_cast<int>(Qt::Unchecked));

но я не уверен, почему это необходимо.

Поскольку они происходят от одного и того же enum, они должны быть одного типа, нет? Я знаю, что существуют потенциальные проблемы, когда два возможных значения являются разными типами, но я не могу понять, почему в этом случае необходимо выполнять приведение типов.

Значения {0, 1, 2} от enum, и я бы подумал, что точно такой же тип исключает любую возможность для преобразования.

Единственная возможность, о которой я могу думать, это то, что нулевое значение перечисления по какой-то причине рассматривается как беззнаковое.

1 Ответ

2 голосов
/ 04 июня 2019

Вместо MCVE я предполагаю, что контекст выглядит примерно так:

struct S
{
    S(int);
    S(unsigned int);
};

S foo()
{
    return (1 ? Qt::Checked : Qt::Unchecked);
}

, который выдает предупреждение в gcc 7.3 :

warning:передача Qt::CheckState выбирает int более unsigned int [-Wsign-promo]


Предупреждение относится к неявному преобразованию значения типа enum CheckState в целое число.Существует допустимое неявное преобразование как в int, так и unsigned int, и разрешение перегрузки выбирает int.

По-видимому, обоснование для предупреждения состоит в том, что некоторые более старые версии gcc выбирают unsigned int в этом сценарии,но gcc 7 следует стандарту и выбирает int.

Ваше исправление работает, потому что второй и третий операнды приводятся к общему типу int до того, как происходит разрешение перегрузки (это не то, чтоперечислитель, который вы выбрали).

Возможно, правильным решением было бы применить static_cast<int> ко всему условному, а не только к одному операнду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...