Можно ли указать типы возврата из побитовой манипуляции? - PullRequest
0 голосов
/ 04 декабря 2018

Большая часть кода в компании, в которой я работаю, часто использует типы знаков без знака для небольших чисел, чтобы избежать нежелательного заполнения в структурах данных.Я редко вижу проблему с этим, однако я столкнулся с небольшой проблемой с неявным преобразованием при установке флагов ошибок с побитовыми операторами.Я нашел обходной путь, просто явный, но мне было интересно, есть ли более элегантный способ.Кстати, мы компилируем с помощью c ++ 11

Учитывая код ошибки enum ниже:

enum ErrorType : unsigned char
{
    OK.     = 0x00,
    ERROR01 = 0x01,
    ERROR02 = 0x02
};

и предполагая, что у меня есть некоторые классы с закрытыми членами типа errorType, которые будут использовать открытые члены для установки илиснять флажки, например:

struct S
{
public:
void setError1();
void unsetError1();

private:
ErrorType errorType;
};

Если я попытаюсь неявно установить значения ниже:

void S::setError1()
{
    this->errorType |= ERROR01;
}

Я получу ошибки преобразования типов

, однако, если я приведу явное приведениепобитовое преобразование работает

this->errorType = ErrorType(this->errorType | ERROR01);

Может показаться, что проблема в том, что выходные данные побитовых преобразований всегда целочисленные и не обязательно отражают тип ввода.Это правда?и если да, есть ли способ указать тип для него, чтобы мне не приходилось каждый раз явным образом приводить?

Ответы [ 3 ]

0 голосов
/ 04 декабря 2018

Когда не существует оператора перегрузки для перечислений, побитовая операция прибегает к версии встроенного оператора, после перевода перечислений в их тип подстилающего, вы можете явно привести его как:

this->errorType = static_cast<ErrorType>(errorType | ERROR01);

или перегрузить|= оператор для разрешения:

ErrorType& operator|=(ErrorType& lhs, ErrorType rhs) {
    lhs = static_cast<ErrorType>(lhs | rhs);
    return lhs;
}

void S::setError1()
{
    this->errorType |= ERROR01;
}
0 голосов
/ 04 декабря 2018

Может показаться, что проблема в том, что выходные данные побитовых преобразований всегда целочисленные и не обязательно отражают тип ввода.Это правда?

С ранних дней C математические операции над типами , меньшими чем int, приведут типы к int.

Причина - когда int был «тип большого целого» - заключалась в том, что повышение до int было бы дешевым и предотвратило бы некоторые ситуации переполнения.

, если так, есть ли способуказать тип для него, чтобы мне не приходилось явно приводить его каждый раз?

Да!Определите операцию, а не принимайте сгенерированную по умолчанию реализацию.

ErrorType& operator |= ( ErrorType &left, ErrorType right )
{
    return left = ErrorType(left | right);
}
0 голосов
/ 04 декабря 2018

Да, результат побитовой операции является целочисленным типом после повышения.Когда два арифметических оператора участвуют в арифметической операции, они сначала повышаются до по крайней мере до типа int, где операция выполняется на int с с результатом int.Не существует неявного преобразования из int в enum, поэтому вы должны сами отбрасывать.

Вот дополнительная информация об интегральных правилах продвижения: https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion

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