Есть ли правильный способ избежать предупреждений при сравнении двух разных перечислений?

При сравнении перечислений из разных источников, например, из следующего кода, GCC выдает предупреждения. Есть ли способ избежать этих предупреждений без приведения c-стиля?

struct Enumerator
{
    enum { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum { VALUE = V };
};

if(Enumerator::VALUE == TemplatedEnumerator<5>::VALUE)
{
  ...
}

И GCC выдает предупреждение следующего типа:

GCC: warning: comparison between 'enum ...' and 'enum ...'

person Robert Gould    schedule 28.01.2009    source источник
comment
Я полагаю, вы застрянете с гипсом.   -  person OJ.    schedule 28.01.2009
comment
struct Enumerator : boost::integral_constant‹int, 5›{}; или даже struct Enumerator : mpl::int_‹4› {}; лучше, чем перечисления имхо. c++1x также будет иметь integer_constant => вы в безопасности в будущем. и затем вы можете просто сравнить ::value разных типов.   -  person Johannes Schaub - litb    schedule 28.01.2009
comment
К сожалению, из-за политики проекта буст запрещен :(   -  person Robert Gould    schedule 28.01.2009


Ответы (5)


Простой ответ в вашем случае: не используйте enum, используйте встроенный static const int:

struct Enumerator
{
    static int const VALUE = 5;
};

template<int V>
struct TemplatedEnumerator
{
    static int const VALUE = V;
};

В этом частном случае это эквивалентно, и все компиляторы последних нескольких лет должны относиться к этому так (я точно знаю, что все основные).

См. также: static const Member Value vs. Member enum: какой метод лучше и почему?

person Konrad Rudolph    schedule 28.01.2009
comment
нужно будет проверить, может быть, это сработает, но эти счетчики делают очень серьезную работу, поэтому я пока не могу сказать - person Robert Gould; 29.01.2009
comment
Попробовал заменить, все получилось, спасибо! Я носил enum хак в своем наборе трюков с тех пор, когда большинство компиляторов не понимали статическую константу правильно! - person Robert Gould; 29.01.2009

Я считаю, что вы можете предоставить свои собственные операторы сравнения, но сначала вам нужно будет назвать перечисления:

struct Enumerator
{
    enum Values { VALUE = 5 };
};

template<int V>
struct TemplatedEnumerator
{
    enum Values { VALUE = V };
};


template <int V>
bool operator==(Enumerator::Values lhs, typename TemplatedEnumerator<V>::Values rhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

template <int V>
bool operator==(typename TemplatedEnumerator<V>::Values rhs, Enumerator::Values lhs)
{
    return static_cast<int>(lhs) == static_cast<int>(rhs);
}

Интересно, что Visual Studio на самом деле не предупреждает о сравнении двух типов перечислителей, а скорее предупреждает о постоянном значении в операторе if — точно так же, как если бы вы сделали это:

if (true) {...}
person Eclipse    schedule 28.01.2009
comment
Я бы очень колебался делать это. Сравнение перечислений разных типов не должно быть чем-то, что просто работает. Хотя иногда в этом есть необходимость, я считаю, что предпочтительнее сделать это явным образом в коде. Вы все еще можете обернуть его во вспомогательную функцию, но перегрузка операторов кажется неправильной. - person philsquared; 28.01.2009
comment
Если эти перечисления существуют только для целей их сравнения (обычного в метапрограммировании шаблонов), то разрешить их сравнение кажется разумным. Обратите внимание, что эти операторы не повлияют на поведение любых других перечислений. - person Eclipse; 28.01.2009
comment
Спасибо за вашу помощь, Джош, но решение Конрада Рудольфа кажется более обновленным, не осознавал, что это действительно сработает, но ваши предположения были правильными. - person Robert Gould; 29.01.2009

Если есть N перечислений, не нужно ли будет N * (N - 1) операторов сравнения? Это может оказаться очень много.

Не могли бы вы просто использовать неявное преобразование перечислений в целые и сделать:

bool equals(int lhs, int rhs)
{
  return lhs == rhs;
}

Тогда вы можете просто сделать это в своем коде:

if(equals(Enumerator::VALUE, TemplatedEnumerator<5>::VALUE))
{
  ...
}

Кроме того, вы можете проверить приведение enum-int: оператор или функция. Принятый ответ говорит, что вам не следует использовать неявное преобразование, но правильно названная функция, такая как equals, должна сделать код очень читабельным и удобным в сопровождении.

person ZaDDaZ    schedule 28.01.2009
comment
вы правы насчет количества кода, но при полной оптимизации они все растают, так что накладных расходов будет не так много - person Robert Gould; 28.01.2009
comment
Если перечислений N - то я бы посчитал это запахом кода. Даже когда N==1 я бы сначала проверил дизайн - но эти вещи время от времени становятся необходимыми. Остальная часть вашего решения в порядке, но equals может быть слишком общим именем для этого. Как насчет CompareDifferentEnums? - person philsquared; 28.01.2009
comment
Присоединяюсь к вопросу о необходимости. Однако я предположил, что это уже рассматривалось при задании вопроса, и, надеюсь, предложил самое простое решение. Однако я не уверен в названии, эта функция будет сравнивать любые значения с целыми числами, а не только с перечислениями. - person ZaDDaZ; 28.01.2009

Не делай этого.

Предупреждение есть, потому что вы не должны смешивать разные перечисления в первую очередь.

Для констант вы можете использовать объявление const.

person starblue    schedule 28.01.2009
comment
Это для метапрограммирования. Мне нужны enums , возможно, для продвинутого уровня для вашего уровня, но это очень распространенный шаблон в C++ для создания кода шаблонов. - person Robert Gould; 28.01.2009
comment
Нет, совет оправдан, перечисления здесь не нужны. - person Konrad Rudolph; 28.01.2009

Вы упускаете очевидный ответ. Нет, не используйте приведение в стиле c. Используйте приведения в стиле C++:

if(static_cast<int>(Enumerator::VALUE) == static_cast<int>(TemplatedEnumerator<5>::VALUE))
{

}

Совершенно безопасно, вполне приемлемо. Два перечисления не являются одним и тем же типом, поэтому если в вашем коде есть что-то подозрительное, это не приведение, а попытка сравнить два разных типа. Но до тех пор, пока вы это делаете, гипс будет моим предпочтительным способом сделать это. Да, вы можете определить оператор сравнения, но приведение типов дает понять, что вы сравниваете два технически несвязанных типа.

person jalf    schedule 28.01.2009