Надоело писать 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;
Слишком неожиданно?
Кто-нибудь так делал?
Есть подводные камни?
Здравствуйте, B0FEE664, Вы писали:
BFE>Надоело писать static_cast'ы и функции для конвертации enum ---> int.
BFE>Слишком неожиданно? BFE>Кто-нибудь так делал?
Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+
Унарный плюс ведь уже делает integral promotion у других типов — удивления меньше.
В том числе для старых unscoped перечислений, которые были до enum class, встроенный плюс используется и работает именно таким образом:
Здравствуйте, watchmaker, Вы писали:
W>Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+ W>Унарный плюс ведь уже делает integral promotion у других типов — удивления меньше.
Здравствуйте, ·, Вы писали:
w>> Достаточно неожиданно встретить перегрузку operator*, когда все для этих целей перегружают унарный operator+
·>Объясните прожженому явщику зачем оператор? Чем явное имя функции хуже?
Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....
·>
·>имхо читается понятнее, чем непонятные иероглифы.
Для меня toInt(..) означает, что у вас в enum'е лежат отрицательные значения. Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum.
А ещё такая функция говорит, что вероятно где-то есть toEnumXXX(int) в которой, вероятно, есть UB (хотя это зависит от версии используемого стандарта).
Здравствуйте, 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 и непонятно какой оператор и куда влепить.
Здравствуйте, ·, Вы писали:
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 и непонятно какой оператор и куда влепить.
С названием функции та же ситуация.
Здравствуйте, B0FEE664, Вы писали:
BFE>·>Объясните прожженому явщику зачем оператор? Чем явное имя функции хуже? BFE>Явное имя, в котором указан тип, подразумевает, что существуют какие-то ещё функции, типа toUInt32, toUShort....
Чем плох to_underlying? Да он появляется только в C++23, но сделать собственную версию — как два пальца об асфальт. Зато сразу понятна семантика, без стеклянных шаров. И никаких намеков на то, что обязано существовать обратное преобразование не видно, по-моему.
Здравствуйте, 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.
Здравствуйте, B0FEE664, Вы писали:
BFE>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.
А вот не совсем все. Когда ты определяешь лямбду внутри функции с формальным параметром auto, ты фактически определяешь локальный класс с шаблонным оператором operator(). На обычных классах это сделать невозможно, потому что определение шаблонов внутри функции (любых) запрещено.
Здравствуйте, rg45, Вы писали:
BFE>>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.
R>А вот не совсем все. Когда ты определяешь лямбду внутри функции с формальным параметром auto, ты фактически определяешь локальный класс с шаблонным оператором operator(). На обычных классах это сделать невозможно, потому что определение шаблонов внутри функции (любых) запрещено.
не аргумент. никто не мешает вынести класс вне функции.
Здравствуйте, night beast, Вы писали:
BFE>Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>.
R>>А вот не совсем все...
NB>не аргумент. никто не мешает вынести класс вне функции.
Можно, конечно. Вопрос только в том, будет ли это "то же самое". Как минимум, изменилась область видимости класса. У класса появилось связывание. Имя классу теперь должен дать программист, а не компилятор.
Здравствуйте, rg45, Вы писали:
R>Можно, конечно. Вопрос только в том, будет ли это "то же самое". Как минимум, изменилась область видимости класса. У класса появилось связывание. Имя классу теперь должен дать программист, а не компилятор.
имхо это все проходит по категории "синтаксический сахар"
Здравствуйте, rg45, Вы писали:
R>Чем плох to_underlying? Да он появляется только в C++23, но сделать собственную версию — как два пальца об асфальт. Зато сразу понятна семантика, без стеклянных шаров. И никаких намеков на то, что обязано существовать обратное преобразование не видно, по-моему.
вот мне кажется, что в стандарте хотели как лучше, а получилось как всегда. std::to_underlying — слишком длинное название для такой часто встречающейся функции. Я использую имя cast. С именем области у меня вопросы. Но можно придумать тоже что-нибудь короткое трёхбуквенное (utl например).
Хорошо бы ещё переопределять операторы << >>. Тогда потребность в таких функциях-костылях отпадает вовсе. Фактически надо то зачастую вычитать из базы, записать в базу, вывести в лог. Внутри всегда использовать тип без приведения. Но это конечно только в теории. На практике функцию cast я леплю постоянно.
Здравствуйте, sergii.p, Вы писали:
SP>вот мне кажется, что в стандарте хотели как лучше, а получилось как всегда. std::to_underlying — слишком длинное название для такой часто встречающейся функции. Я использую имя cast. С именем области у меня вопросы. Но можно придумать тоже что-нибудь короткое трёхбуквенное (utl например). SP>
По моему опыту, удачные имена — вовсе не обязательно наиболее короткие. По имени cast трудно понять тип результата. Придется напрягаться и угадывать при чтении. Имхо, лучше написать более длинное имя и исключить любые недопонимания.
Здравствуйте, B0FEE664, Вы писали:
R>>Чем плох to_underlying? Да он появляется только в C++23... BFE>слишком длинное имя, но можно и его использовать, конечно.
Я же не предлагаю тебе использовать именно это имя. Это просто как образец подхода.
Хотя, как по мне, соотношение информативность/длина вполне адекватное. По-моему это лучше, чем когда унарный плюс используется для преобразования типов.
Здравствуйте, B0FEE664, Вы писали:
R>>Чем плох to_underlying? Да он появляется только в C++23... BFE>слишком длинное имя, но можно и его использовать, конечно.
Ты всё ешё в нотепаде код что-ли пишешь? В эпоху современных IDE это давно не проблема.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали: ·>Не, я имею в виду, вместо того, чтобы писать "+" лучше определять "asOrdinal" (или по вкусу) для всех enum. ·>Разница лишь в имени. Вместо "*" будет "asOrdinal", остальное всё так же.
Чем лучше? BFE>> Синтаксический сахар. Это как с лямбдами — и до них можно было всё тоже самое, но введение нового синтаксиса сильно упростило применение функций из <algorithm>. ·>Лямбды имеют новую семантику — захват контекста и значительно всё упрощают, т.к. не надо определять тип отдельно.
Захват контекста можно сделать с помощью отдельного типа. ·>А тут — неясно, т.к. разница чисто синтаксическая.
Вот поэтому я и задал исходный вопрос. BFE>> BFE>> Это уже подозрительно. Такой код означает, что надо проверять, что там fn(..) делает и какие значения у enum. BFE>> ·>operator+ чем поможет? BFE>> А он не указывает тип возвращаемого значения. ·>Не понял. А asOrdinal чем хуже?
Ordinal? Надо проверить, нет ли специального класса с таким именем. Если выбирать имя, то to_underlying, как подсказал rg45. BFE>> ·>Суть в том, что видя первый раз в жизни +Foo я не понимаю что тут хотят сказать и даже неясно как догадаться — надо лезть в доку. asOrdinal(Foo) — сразу ясно — взять порядковое значение енума. BFE>> И не факт, что чтение доки поможет. Мне, например, не помогло. ·>Что не помогло? Не понял.
Это старая тема. Есть ещё случай, где используется унарный плюс:
BFE>> ·>Да, действительно. Захочется превратить int обратно в enum и непонятно какой оператор и куда влепить. BFE>> С названием функции та же ситуация. ·>В смысле? Ты сам же написал asEnum. Единственное она должна быть шаблонной или просто overload по разным типам enum.
Это выглядит не очень красиво: