operator* для enum class
От: B0FEE664  
Дата: 21.09.21 09:15
Оценка: 7 (2) :))
Надоело писать static_cast'ы и функции для конвертации enum ---> int.

А что если перегрузить оператор * :

enum class TestE
{
   a,
   b
};

unsigned int operator* (TestE x)
{
   return TestE::a == x ? 0 : 1;
};


   TestE asdf = TestE::b;

   unsigned int v = *asdf;
   unsigned int vv = *TestE::b;


Слишком неожиданно?
Кто-нибудь так делал?
Есть подводные камни?

тест
И каждый день — без права на ошибку...
Re: operator* для enum class
От: watchmaker  
Дата: 21.09.21 09:29
Оценка: 13 (4) +1
Здравствуйте, B0FEE664, Вы писали:

BFE>Надоело писать static_cast'ы и функции для конвертации enum ---> int.


BFE>Слишком неожиданно?

BFE>Кто-нибудь так делал?

Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+
Унарный плюс ведь уже делает integral promotion у других типов — удивления меньше.

В том числе для старых unscoped перечислений, которые были до enum class, встроенный плюс используется и работает именно таким образом:
enum Enum {
    Foo
};

void fn(Enum);
void fn(int);

void test() {
    fn(Foo);   // вызов перегрузки  void fn(Enum)
    fn(+Foo);  // вызов перегрузки  void fn(int)
}


BFE>unsigned int operator* (TestE x)

BFE>{
BFE> return TestE::a == x ? 0 : 1;
BFE>};
В эту сторону проще сделать (возможно в шаблоне для всех enum)

return static_cast<std::underlying_type_t<TestE>>(x);

и навсегда забыть об ручном выписывании значений.
Отредактировано 23.09.2021 10:35 watchmaker . Предыдущая версия . Еще …
Отредактировано 22.09.2021 20:14 watchmaker . Предыдущая версия .
Re[2]: operator* для enum class
От: B0FEE664  
Дата: 21.09.21 09:43
Оценка:
Здравствуйте, watchmaker, Вы писали:

W>Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+

W>Унарный плюс ведь уже делает integral promotion у других типов — удивления меньше.

Что-ж. Плюс, так плюс. Так и запишем.
И каждый день — без права на ошибку...
Re[2]: operator* для enum class
От: · Великобритания  
Дата: 23.09.21 12:06
Оценка: +3
Здравствуйте, watchmaker, Вы писали:

w> Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+


Объясните прожженому явщику зачем оператор? Чем явное имя функции хуже?
 void test() {
     fn(Foo);   // вызов перегрузки  void fn(Enum)
     fn(toInt(Foo));  // вызов перегрузки  void fn(int)
 }

имхо читается понятнее, чем непонятные иероглифы.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[3]: operator* для enum class
От: B0FEE664  
Дата: 23.09.21 13:40
Оценка:
Здравствуйте, ·, Вы писали:

w>> Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+


·>Объясните прожженому явщику зачем оператор? Чем явное имя функции хуже?

Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....

·>
·> void test() {
·>     fn(Foo);   // вызов перегрузки  void fn(Enum)
·>     fn(toInt(Foo));  // вызов перегрузки  void fn(int)
·> }
·>

·>имхо читается понятнее, чем непонятные иероглифы.

Для меня toInt(..) означает, что у вас в enum'е лежат отрицательные значения. Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.

А ещё такая функция говорит, что вероятно где-то есть toEnumXXX(int) в которой, вероятно, есть UB (хотя это зависит от версии используемого стандарта).
И каждый день — без права на ошибку...
Re[4]: operator* для enum class
От: · Великобритания  
Дата: 23.09.21 13:56
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE> Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....

ок, пусть toUInt() или вообще asOrdinal() или asNumber().

Но всё равно сово-глобусный аргумент. Ведь наличие operator+ явно подразумевает наличие и -*/^ и т.п.

BFE> Для меня toInt(..) означает, что у вас в enum'е лежат отрицательные значения.

Ну в коде был int я так и написал. Какой тип использовать — это другой вопрос. Я пытаюсь понять мотивацию выбора неявного значка вместо явного слова.

BFE> Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.

operator+ чем поможет?

Суть в том, что видя первый раз в жизни +Foo я не понимаю что тут хотят сказать и даже неясно как догадаться — надо лезть в доку. asOrdinal(Foo) — сразу ясно — взять порядковое значение енума.

BFE> А ещё такая функция говорит, что вероятно где-то есть toEnumXXX(int) в которой, вероятно, есть UB (хотя это зависит от версии используемого стандарта).

Да, действительно. Захочется превратить int обратно в enum и непонятно какой оператор и куда влепить.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: operator* для enum class
От: B0FEE664  
Дата: 23.09.21 14:24
Оценка:
Здравствуйте, ·, Вы писали:

BFE>> Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....

·>ок, пусть toUInt() или вообще asOrdinal() или asNumber().
·>Но всё равно сово-глобусный аргумент.
Вот и получается, что для каждого enum какая-то своя функция, не такая, как у другого enum, а хочется унификации.

·>Ведь наличие operator+ явно подразумевает наличие и -*/^ и т.п.

Это да. Мне ближе в этом плане operator*, как у смарт указателей, но... смотри ответ watchmaker.

BFE>> Для меня toInt(..) означает, что у вас в enum'е лежат отрицательные значения.

·>Ну в коде был int я так и написал. Какой тип использовать — это другой вопрос. Я пытаюсь понять мотивацию выбора неявного значка вместо явного слова.
Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.

BFE>> Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.

·>operator+ чем поможет?
А он не указывает тип возвращаемого значения.

·>Суть в том, что видя первый раз в жизни +Foo я не понимаю что тут хотят сказать и даже неясно как догадаться — надо лезть в доку. asOrdinal(Foo) — сразу ясно — взять порядковое значение енума.

И не факт, что чтение доки поможет. Мне, например, не помогло.

BFE>> А ещё такая функция говорит, что вероятно где-то есть toEnumXXX(int) в которой, вероятно, есть UB (хотя это зависит от версии используемого стандарта).

·>Да, действительно. Захочется превратить int обратно в enum и непонятно какой оператор и куда влепить.
С названием функции та же ситуация.
И каждый день — без права на ошибку...
Отредактировано 23.09.2021 15:13 B0FEE664 . Предыдущая версия .
Re[4]: operator* для enum class
От: rg45 СССР  
Дата: 23.09.21 14:47
Оценка: +3
Здравствуйте, B0FEE664, Вы писали:

BFE>·>Объясните прожженому явщику зачем оператор? Чем явное имя функции хуже?

BFE>Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....

Чем плох to_underlying? Да он появляется только в C++23, но сделать собственную версию — как два пальца об асфальт. Зато сразу понятна семантика, без стеклянных шаров. И никаких намеков на то, что обязано существовать обратное преобразование не видно, по-моему.
--
Отредактировано 23.09.2021 14:54 rg45 . Предыдущая версия .
Re[6]: operator* для enum class
От: · Великобритания  
Дата: 23.09.21 20:33
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE> ·>ок, пусть toUInt() или вообще asOrdinal() или asNumber().

BFE> ·>Но всё равно сово-глобусный аргумент.
BFE> Вот и получается, что для каждого enum какая-то своя функция, не такая, как у другого enum, а хочется унификации.
Не, я имею в виду, вместо того, чтобы писать "+" лучше определять "asOrdinal" (или по вкусу) для всех enum.

Разница лишь в имени. Вместо "*" будет "asOrdinal", остальное всё так же.

BFE> BFE>> Для меня toInt(..) означает, что у вас в enum'е лежат отрицательные значения.

BFE> ·>Ну в коде был int я так и написал. Какой тип использовать — это другой вопрос. Я пытаюсь понять мотивацию выбора неявного значка вместо явного слова.
BFE> Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.
Лямбды имеют новую семантику — захват контекста и значительно всё упрощают, т.к. не надо определять тип отдельно. А тут — неясно, т.к. разница чисто синтаксическая.

BFE> BFE>> Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.

BFE> ·>operator+ чем поможет?
BFE> А он не указывает тип возвращаемого значения.
Не понял. А asOrdinal чем хуже?

BFE> ·>Суть в том, что видя первый раз в жизни +Foo я не понимаю что тут хотят сказать и даже неясно как догадаться — надо лезть в доку. asOrdinal(Foo) — сразу ясно — взять порядковое значение енума.

BFE> И не факт, что чтение доки поможет. Мне, например, не помогло.
Что не помогло? Не понял.

BFE> ·>Да, действительно. Захочется превратить int обратно в enum и непонятно какой оператор и куда влепить.

BFE> С названием функции та же ситуация.
В смысле? Ты сам же написал asEnum. Единственное она должна быть шаблонной или просто overload по разным типам enum.
avalon/3.0.0
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[6]: operator* для enum class
От: rg45 СССР  
Дата: 23.09.21 21:29
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.


А вот не совсем все. Когда ты определяешь лямбду внутри функции с формальным параметром auto, ты фактически определяешь локальный класс с шаблонным оператором operator(). На обычных классах это сделать невозможно, потому что определение шаблонов внутри функции (любых) запрещено.
--
Отредактировано 23.09.2021 21:37 rg45 . Предыдущая версия . Еще …
Отредактировано 23.09.2021 21:31 rg45 . Предыдущая версия .
Re[7]: operator* для enum class
От: night beast СССР  
Дата: 24.09.21 06:02
Оценка:
Здравствуйте, rg45, Вы писали:

BFE>>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.


R>А вот не совсем все. Когда ты определяешь лямбду внутри функции с формальным параметром auto, ты фактически определяешь локальный класс с шаблонным оператором operator(). На обычных классах это сделать невозможно, потому что определение шаблонов внутри функции (любых) запрещено.


не аргумент. никто не мешает вынести класс вне функции.
Re[8]: operator* для enum class
От: rg45 СССР  
Дата: 24.09.21 06:26
Оценка:
Здравствуйте, night beast, Вы писали:

BFE>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.


R>>А вот не совсем все...


NB>не аргумент. никто не мешает вынести класс вне функции.


Можно, конечно. Вопрос только в том, будет ли это "то же самое". Как минимум, изменилась область видимости класса. У класса появилось связывание. Имя классу теперь должен дать программист, а не компилятор.
--
Отредактировано 24.09.2021 6:33 rg45 . Предыдущая версия . Еще …
Отредактировано 24.09.2021 6:30 rg45 . Предыдущая версия .
Отредактировано 24.09.2021 6:30 rg45 . Предыдущая версия .
Отредактировано 24.09.2021 6:27 rg45 . Предыдущая версия .
Re[9]: operator* для enum class
От: night beast СССР  
Дата: 24.09.21 06:42
Оценка: +2
Здравствуйте, rg45, Вы писали:

R>Можно, конечно. Вопрос только в том, будет ли это "то же самое". Как минимум, изменилась область видимости класса. У класса появилось связывание. Имя классу теперь должен дать программист, а не компилятор.


имхо это все проходит по категории "синтаксический сахар"
Re[5]: operator* для enum class
От: sergii.p  
Дата: 24.09.21 07:46
Оценка:
Здравствуйте, rg45, Вы писали:

R>Чем плох to_underlying? Да он появляется только в C++23, но сделать собственную версию — как два пальца об асфальт. Зато сразу понятна семантика, без стеклянных шаров. И никаких намеков на то, что обязано существовать обратное преобразование не видно, по-моему.


вот мне кажется, что в стандарте хотели как лучше, а получилось как всегда. std::to_underlying — слишком длинное название для такой часто встречающейся функции. Я использую имя cast. С именем области у меня вопросы. Но можно придумать тоже что-нибудь короткое трёхбуквенное (utl например).
enum class UserId{};
UserId id;
std::cout << "User id: " << utl::cast(id);


Хорошо бы ещё переопределять операторы << >>. Тогда потребность в таких функциях-костылях отпадает вовсе. Фактически надо то зачастую вычитать из базы, записать в базу, вывести в лог. Внутри всегда использовать тип без приведения. Но это конечно только в теории. На практике функцию cast я леплю постоянно.
Re[6]: operator* для enum class
От: rg45 СССР  
Дата: 24.09.21 07:50
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>вот мне кажется, что в стандарте хотели как лучше, а получилось как всегда. std::to_underlying — слишком длинное название для такой часто встречающейся функции. Я использую имя cast. С именем области у меня вопросы. Но можно придумать тоже что-нибудь короткое трёхбуквенное (utl например).

SP>
SP>enum class UserId{};
SP>UserId id;
SP>std::cout << "User id: " << utl::cast(id);
SP>


По моему опыту, удачные имена — вовсе не обязательно наиболее короткие. По имени cast трудно понять тип результата. Придется напрягаться и угадывать при чтении. Имхо, лучше написать более длинное имя и исключить любые недопонимания.
--
Отредактировано 24.09.2021 7:52 rg45 . Предыдущая версия .
Re[5]: operator* для enum class
От: B0FEE664  
Дата: 24.09.21 07:57
Оценка: :)
Здравствуйте, rg45, Вы писали:

R>Чем плох to_underlying? Да он появляется только в C++23...

слишком длинное имя, но можно и его использовать, конечно.
И каждый день — без права на ошибку...
Re[6]: operator* для enum class
От: rg45 СССР  
Дата: 24.09.21 07:59
Оценка: +3
Здравствуйте, B0FEE664, Вы писали:

R>>Чем плох to_underlying? Да он появляется только в C++23...

BFE>слишком длинное имя, но можно и его использовать, конечно.

Я же не предлагаю тебе использовать именно это имя. Это просто как образец подхода.

Хотя, как по мне, соотношение информативность/длина вполне адекватное. По-моему это лучше, чем когда унарный плюс используется для преобразования типов.
--
Отредактировано 24.09.2021 8:07 rg45 . Предыдущая версия . Еще …
Отредактировано 24.09.2021 8:00 rg45 . Предыдущая версия .
Re[6]: operator* для enum class
От: · Великобритания  
Дата: 24.09.21 09:23
Оценка:
Здравствуйте, B0FEE664, Вы писали:

R>>Чем плох to_underlying? Да он появляется только в C++23...

BFE>слишком длинное имя, но можно и его использовать, конечно.
Ты всё ешё в нотепаде код что-ли пишешь? В эпоху современных IDE это давно не проблема.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: operator* для enum class
От: B0FEE664  
Дата: 24.09.21 09:42
Оценка:
Здравствуйте, ·, Вы писали:

·>Не, я имею в виду, вместо того, чтобы писать "+" лучше определять "asOrdinal" (или по вкусу) для всех enum.

·>Разница лишь в имени. Вместо "*" будет "asOrdinal", остальное всё так же.
Чем лучше?

BFE>> Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.

·>Лямбды имеют новую семантику — захват контекста и значительно всё упрощают, т.к. не надо определять тип отдельно.
Захват контекста можно сделать с помощью отдельного типа.

·>А тут — неясно, т.к. разница чисто синтаксическая.

Вот поэтому я и задал исходный вопрос.

BFE>> BFE>> Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.

BFE>> ·>operator+ чем поможет?
BFE>> А он не указывает тип возвращаемого значения.
·>Не понял. А asOrdinal чем хуже?
Ordinal? Надо проверить, нет ли специального класса с таким именем. Если выбирать имя, то to_underlying, как подсказал rg45.

BFE>> ·>Суть в том, что видя первый раз в жизни +Foo я не понимаю что тут хотят сказать и даже неясно как догадаться — надо лезть в доку. asOrdinal(Foo) — сразу ясно — взять порядковое значение енума.

BFE>> И не факт, что чтение доки поможет. Мне, например, не помогло.
·>Что не помогло? Не понял.
Это старая тема. Есть ещё случай, где используется унарный плюс:
  Скрытый текст
проверка
#include <iostream>
#include <chrono>

class A
{
public:
  static const unsigned TIMEOUT = 300;
};


void foo(std::chrono::milliseconds timeout)
{
}


void boo()
{
  foo( std::chrono::milliseconds(A::TIMEOUT) );
  //foo( std::chrono::milliseconds(+A::TIMEOUT) ); //OK
}


int main()
{
    std::cout << "the end\n";
    return 0;
}


BFE>> ·>Да, действительно. Захочется превратить int обратно в enum и непонятно какой оператор и куда влепить.

BFE>> С названием функции та же ситуация.
·>В смысле? Ты сам же написал asEnum. Единственное она должна быть шаблонной или просто overload по разным типам enum.
Это выглядит не очень красиво:
auto en = AsEnum<SomeEnumeName>(x);
И каждый день — без права на ошибку...
Re[6]: operator* для enum class
От: RonWilson Россия  
Дата: 24.09.21 09:54
Оценка:
Здравствуйте, B0FEE664, Вы писали:

BFE>слишком длинное имя, но можно и его использовать, конечно.


и такое встречается и живут люди, ничего:

#define Convert_EnumValue_To_Integer(x) ((int)x)
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.