Оператор присваивания для enum class
От: Dmitry Vinogradov  
Дата: 11.12.15 15:58
Оценка:
Подскажите, пожалуйста, как написать оператор присваивания для enum class?

Мне приходит в голову такой вариант:
#include "assert.h"

enum class A
{
  a1,
  a2
};


enum class B
{
  b1,
  b2
};


void operator <=(A& a, B b)
{
    switch(b)
    {
        case B::b1: a = A::a1; return;
        case B::b2: a = A::a2; return;
    }
    assert(false);
}

int main(int argc, char* argv[])
{
    A a = A::a1;
    B b = B::b2;
    a <= b;
    return 0;
}


Есть ли способ лучше?
Чем можно заменить switch в operator <=(A&, B) ?
Re: Оператор присваивания для enum class
От: Кодт Россия  
Дата: 11.12.15 16:40
Оценка:
Здравствуйте, Dmitry Vinogradov, Вы писали:

DV>Подскажите, пожалуйста, как написать оператор присваивания для enum class?

DV>Есть ли способ лучше?

Плохая идея — перегрузить оператор "меньше-или-равно". Слишком уж радикально меняется семантика, да и с приоритетами неловко выйдет.
Такое позволительно в expression template каких-нибудь, где делается DSL из подручного материала.

Я бы предпочёл написать функцию явного приведения
enum class A { ... };
enum class B { ... };

A toA(A a) { return a; }
A toA(B b) { ... }


DV>Чем можно заменить switch в operator <=(A&, B) ?


switch — вполне себе неплохое решение, компилятор сам догадается, как его эффективно (или неэффективно) реализовать: арифметикой, таблицей, двоичным поиском, линейным поиском.
Но если опыты показывают, что компилятор затупил, то — то же самое можно и вручную сделать
enum class A { a1, a2 };
enum class B { b2, b1 };

A toA(B b) {
  // арифметикой
  return (A)(1-(int)b);

  // таблицей
  static const A aaa[] = { a2, a1 };
  return aaa[(int)b];

  // поиском (лень писать эффективный код, оставлю эскиз)
  static const pair<A,B> ab[] = { make_pair(a1,b1), make_pair(a2,b2) };
  return find_if(begin(ab), end(ab), [b](auto const& xy) { return xy.second == b; })->first;
}
Перекуём баги на фичи!
Re[2]: Оператор присваивания для enum class
От: Dmitry Vinogradov  
Дата: 11.12.15 17:10
Оценка:
Здравствуйте, Кодт, Вы писали:

К>... да и с приоритетами неловко выйдет.

А что не так с приоритетом, если учесть, что operator возвращает void? В какой ситуации это может быть проблемой?

К>Я бы предпочёл написать функцию явного приведения

Вот от таких явнах функций конвертирования хочется отказаться.
Re: Оператор присваивания для enum class
От: Alexander G Украина  
Дата: 11.12.15 18:27
Оценка:
Здравствуйте, Dmitry Vinogradov, Вы писали:


DV>void operator <=(A& a, B b)


Стрёмная семантика для этого оператора.
Кроме того, неудобно, потребуется объявлять переменную там, где хватило бы временного объекта (передача в функцию, возвращение значения из функции — как основные примеры).

DV>Есть ли способ лучше?


Вообще функция лучше

A AfromB(B);


Хочется инфиксного присвоения, как у меньше равно, то

struct AfromB
{
  AfromB(B);
  operator A();
};

a =(AfromB) b
Русский военный корабль идёт ко дну!
Re: Оператор присваивания для enum class
От: Alexander G Украина  
Дата: 11.12.15 18:58
Оценка:
Здравствуйте, Dmitry Vinogradov, Вы писали:
    switch(b)
    {
        case B::b1: a = A::a1; return;
        case B::b2: a = A::a2; return;
    }
    assert(false);


Кстати, имеется возможность помимо проверки времени выполнения assert(false) добавить проверку времени компиляции, что все значения перечислены.
(Но это специфично для конкретных компиляторов)

Для Visual C++ — превратить в ошибку предупреждение C4062 (которое по умолчанию вообще выключено) перед методом конвертации.
__pragma(warning(push))
__pragma(warning(error: 4062))

После метода — вернуть как было.
__pragma(warning(pop))

(можно обойтись без push/pop, если в пределах текущей единицы трансляции эта ошибка мешать не будет)

Для gcc соответственно
_Pragma("GCC diagnostic push")
_Pragma("GCC diagnostic error \"-Wswitch\"")

и
_Pragma("GCC diagnostic pop")
Русский военный корабль идёт ко дну!
Re[3]: Оператор присваивания для enum class
От: Кодт Россия  
Дата: 13.12.15 12:13
Оценка:
Здравствуйте, Dmitry Vinogradov, Вы писали:

К>>... да и с приоритетами неловко выйдет.

DV>А что не так с приоритетом, если учесть, что operator возвращает void? В какой ситуации это может быть проблемой?

enum class Antigenes { O, A, B, AB };
Antigenes operator | (Antigenes x, Antigenes y) { return (Antigenes)((int)x | (int)y); }

enum class Group { I, II, III, IV };
void operator <= (Group& dst, Antigenes src) { dst = (Group)src; }

int main() {
    Group g;
    g <= Antigenes::A | Antigenes::B; // какого чёрта оно не компилится?!!!
// (g <= Antigenes::A)| Antigenes::B; // а вот какого.
}


К>>Я бы предпочёл написать функцию явного приведения

DV>Вот от таких явнах функций конвертирования хочется отказаться.

Чем вычурный синтаксис предпочтительнее лишних букв в тексте?
Перекуём баги на фичи!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.