Действительно ли я могу перегрузить операторы на перечислимых типах в C++?

Например, если я имею:

typedef enum { year, month, day } field_type;

inline foo operator *(field_type t,int x)
{
   return foo(f,x);
}
inline foo operator -(field_type t)
{
   return t*-1;
}
int operator /(distance const &d,field_type v)
{
  return d.in(v);
}

Поскольку, если я не определяю такие операторы, на самом деле законно записать day*3 и это было бы переведено в 6?

Таким образом, действительно ли это законно?

По крайней мере, gcc и компилятор Intel принимают это без предупреждения.

Clearification:

Я не хочу арифметические операции по умолчанию, я хочу свои собственные операции тот тип нецелого числа возврата.

15
задан P Daddy 6 March 2010 в 18:11
поделиться

4 ответа

Да, перегрузка оператора может выполняться для типов перечислений и классов. То, как вы это делаете, нормально, но вы должны использовать + для продвижения перечисления вместо * - 1 или чего-то подобного (цель в конечном итоге состоит в том, чтобы избежать бесконечной рекурсии, потому что -t ):

inline foo operator -(field_type t) {
   return -+t;
}

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


Обратите внимание, что ваш оператор * позволяет использовать только enum_type * integer , но не наоборот. Возможно, стоит подумать и о другом направлении.

Также обратите внимание, что всегда немного опасно перегружать операторы для операндов, которые встроенные операторы уже принимают (даже если только путем неявных преобразований). Представьте, что distance имеет конструктор преобразования, принимающий int (как в distance (int) ), а затем, учитывая ваш operator / , следующее неоднозначно

// ambiguous: operator/(int, int) (built-in) or
//            operator/(distance const&, field_type) ?
31 / month;

Для этого , может быть, лучше сделать field_type реальным классом с соответствующими операторами, чтобы с самого начала можно было исключить любое из таких неявных преобразований. Еще одно хорошее решение - это класс перечисления C ++ 0x , который обеспечивает строгие перечисления.

7
ответ дан 1 December 2019 в 05:11
поделиться

Если вы спрашиваете, является ли этот код legal:

enum A {
    x,y
};

int main() {
    int z = x * y;
}

Ответ, к сожалению, «да». Существует неявное преобразование значений перечисления в целые числа.

1
ответ дан 1 December 2019 в 05:11
поделиться

Что ж, ответ на ваш вопрос о день * 3 : да, вы можете это сделать. Для этого не требуется перегрузка оператора. И результат будет 6 . Однако это будет работать, если ваша константа day будет преобразована в тип int , произведено умножение внутри типа int и получится результат типа int ], т.е. что 6 - это int . Отсюда возникает следующий вопрос: согласны ли вы с тем, что это int ? Что вы собираетесь делать с этим 6 потом? Если int подходит для ваших целей, вам не нужно ничего делать.

Однако возможно, что вы действительно хотите получить результат типа field_type из день * 3 . Видите ли, в C ++ тип int не может быть явно преобразован в типы enum.Таким образом, это будет компилироваться и работать

int product = day * 3;

, но не будет

field_type product = day * 3; // ERROR

. Вы можете принудительно выполнить компиляцию последнего, используя явное приведение

field_type product = (field_type) (day * 3);

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

field_type operator *(field_type lhs, int rhs)
{
  return (field_type) ((int) lhs * rhs)
}

. Обратите внимание, что реализация перегруженный оператор по-прежнему полагается на приведение, так что это всего лишь способ сделать «основной» код вашей программы более чистым путем инкапсуляции уродливых приведений в специальные операторы (в этом нет ничего плохого).

В качестве педантичного побочного примечания я хотел бы добавить, что есть определенные формальные опасности при попытке сжать результаты целочисленных арифметических операций в типе перечисления (если это то, что вы хотите; возможно, вы этого не сделаете, так как вы похоже, для результата используется какой-то другой тип foo ). Диапазон значений, которые может представлять объект перечисления, [примерно] определяется максимальным (по величине) значением константы перечисления, округленным до следующего по величине (по величине) числа в форме 2 ^ N-1 . В вашем случае максимальное значение день равно 2, что означает, что ваше перечисление гарантированно точно представляет значения до 3 . Если вы попытаетесь преобразовать 6 в ваш тип перечисления, результат будет неопределенным (хотя на практике он обычно работает «как ожидалось»).

0
ответ дан 1 December 2019 в 05:11
поделиться

Да, это законно. ENUM автоматически превращает значения в INT.

-1
ответ дан 1 December 2019 в 05:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: