Подскажите, пожалуйста, как написать оператор присваивания для 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) ?
Здравствуйте, 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;
}
Здравствуйте, Кодт, Вы писали:
К>... да и с приоритетами неловко выйдет.
А что не так с приоритетом, если учесть, что operator возвращает void? В какой ситуации это может быть проблемой?
К>Я бы предпочёл написать функцию явного приведения
Вот от таких явнах функций конвертирования хочется отказаться.
Стрёмная семантика для этого оператора.
Кроме того, неудобно, потребуется объявлять переменную там, где хватило бы временного объекта (передача в функцию, возвращение значения из функции — как основные примеры).
DV>Есть ли способ лучше?
Вообще функция лучше
A AfromB(B);
Хочется инфиксного присвоения, как у меньше равно, то
struct AfromB
{
AfromB(B);
operator A();
};
a =(AfromB) b
switch(b)
{
case B::b1: a = A::a1; return;
case B::b2: a = A::a2; return;
}
assert(false);
Кстати, имеется возможность помимо проверки времени выполнения assert(false) добавить проверку времени компиляции, что все значения перечислены.
(Но это специфично для конкретных компиляторов)
Для Visual C++ — превратить в ошибку предупреждение C4062 (которое по умолчанию вообще выключено) перед методом конвертации.
Здравствуйте, 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>Вот от таких явнах функций конвертирования хочется отказаться.
Чем вычурный синтаксис предпочтительнее лишних букв в тексте?