Как бы поизящнее прикрутить к enum ограничение области видимости в версиях до C++11?
Я пока не придумал ничего лучшего, чем заворачивать enum в одноименный namespace, но тогда на имя типа приходится ссылаться конструкцией вида EnumType::EnumType, что выглядит как-то коряво.
смотря чем ограничена эта область
кроме неймспейса еще можно структурой или классом оборачивать
и виден такой енум будет соответственно только в пределах класса или структуры
Здравствуйте, reversecode, Вы писали:
R>кроме неймспейса еще можно структурой или классом оборачивать R>и виден такой енум будет соответственно только в пределах класса или структуры
Это понятно. Тут основная проблема в том, чтобы определить константы с простыми, не уникальными именами вроде Day, Out или Upper. В scoped enum доступ к ним возможен только через квалификатор имени типа, и все выглядит очень изящно. Хочется сделать нечто похожее в C++03, но не слишком коряво.
для того их и улучшали в С++11 что бы поубирать эти ограничения
ну пусть будут
e_day, e_month e_upper
или
eDay, eMoth eUpper и никогда не было проблем
или
enum SomeStatusValue { ssValue1, ssValue2, ssValue3 };
поизучайте всякие code style
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Как бы поизящнее прикрутить к enum ограничение области видимости в версиях до C++11?
ЕМ>Я пока не придумал ничего лучшего, чем заворачивать enum в одноименный namespace, но тогда на имя типа приходится ссылаться конструкцией вида EnumType::EnumType, что выглядит как-то коряво.
А что именно коряво?
struct Bit { enum { B0=1, B1=2, B2=4, B3=8 }; };
//int x = Bit::B0 | Bit::B2;
Здравствуйте, kov_serg, Вы писали:
R>>>Bit x = Bit::B0 | Bit::B2;
ЕМ>>Именно.
_>Зачем?
Затем, чтоб компилятор отслеживал тип переменной, и обламывал ошибочные попытки присвоить ей произвольное числовое значение. Я б с удовольствием запретил и преобразование enum в int по умолчанию, оставив только явное, но компиляторы такого не умеют.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Затем, чтоб компилятор отслеживал тип переменной, и обламывал ошибочные попытки присвоить ей произвольное числовое значение. Я б с удовольствием запретил и преобразование enum в int по умолчанию, оставив только явное, но компиляторы такого не умеют.
Я использую примерно такой подход:
struct Color
{
enum t
{
Red,
Green,
Blue
};
};
При указании типа следует использовать Color::t, константы указываются как Color::Red, Color::Green и Color::Blue.
При попытке присвоить Color::t "что-нибудь" компилятор обычно ругается.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Здравствуйте, kov_serg, Вы писали:
R>>>>Bit x = Bit::B0 | Bit::B2;
ЕМ>>>Именно.
_>>Зачем?
ЕМ>Затем, чтоб компилятор отслеживал тип переменной, и обламывал ошибочные попытки присвоить ей произвольное числовое значение. Я б с удовольствием запретил и преобразование enum в int по умолчанию, оставив только явное, но компиляторы такого не умеют.
Вам не кажется что это доведение до абсурда?
Може вы еще и такие типы хотите PositiveDouble, RangeDouble, MultiRangeDouble, DoubleWithAcceptedValues
и еще такие DoubleMeter, FloatTime, LongDoubleMass ...
И потом трахаетесь с их преобразованиями?
Может лучше не плодить сущности, пораждаю лишнюю энтропию, а использовать по максимуму имеющиеся?
О, спасибо. Я такое тоже использую с namespace, когда имя типа можно естественным образом разделить на названия двух независимых сущностей, а вот когда разделить нельзя — не придумал ничего лучше, чем давать одинаковые имена и тому, и другому. Вроде бы очевидная и элементарная идея, а вот не пришла в голову.
Здравствуйте, kov_serg, Вы писали:
_>Вам не кажется что это доведение до абсурда?
Никоим образом. Если в языке есть идея строгой типизации — ее нужно использовать везде, кроме исключительных случаев.
_>Може вы еще и такие типы хотите PositiveDouble, RangeDouble, MultiRangeDouble, DoubleWithAcceptedValues _>и еще такие DoubleMeter, FloatTime, LongDoubleMass ...
Не хочу. По той простой причине, что тип double предназначен для вычислений, и диапазон его значений по определению не имеет разрывов, кроме пары неопределенностей. А тип enum, наоборот, для вычислений по определению не предназначен, и его значения не обязаны быть смежными. По сути, это такой примитивный аналог множества с постоянной мощностью 1, из которого можно принудительно сделать множества мощностью до 32-64.
_>Может лучше не плодить сущности, пораждаю лишнюю энтропию, а использовать по максимуму имеющиеся?
Имеющиеся сущности лучше использовать, когда они добавляют читабельности, безопасности и эффективности. Я бы хотел иметь в языке еще несколько возможностей для ограничения свободы компилятора по неявному преобразованию типов, а также пару десятков дополнительных предупреждений.
Изящные решения. Но в критичных по времени конструкциях нужно использовать с осторожностью — на элементарные с виду конструкции компилятор в отладочном режиме нагенерит много кода, да еще с вызовами, скоростью может резко упасть.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Не хочу. По той простой причине, что тип double предназначен для вычислений, и диапазон его значений по определению не имеет разрывов, кроме пары неопределенностей. А тип enum, наоборот, для вычислений по определению не предназначен, и его значения не обязаны быть смежными. По сути, это такой примитивный аналог множества с постоянной мощностью 1, из которого можно принудительно сделать множества мощностью до 32-64.
Вот например функция sqrt ждёт положительные значения, asin значение из диапазона [-1..1]. Так что вполне можно использовать типы с ограничениями. Более того иногда хочется проверки на переполнения например у целых чисел.
ЕМ>Имеющиеся сущности лучше использовать, когда они добавляют читабельности, безопасности и эффективности. Я бы хотел иметь в языке еще несколько возможностей для ограничения свободы компилятора по неявному преобразованию типов, а также пару десятков дополнительных предупреждений.
Всё же вы видимо хотите ограничивать не компилятор, а программистов которые будут работать с этим кодом.
Вам стоит использовать не C++, он явно преследует иные цели.
Здравствуйте, kov_serg, Вы писали:
_>Вот например функция sqrt ждёт положительные значения, asin значение из диапазона [-1..1].
Здесь нужны не типы с ограничениями, а встроенные проверки в этих функциях — хотя бы в отладочных конфигурациях.
_>Так что вполне можно использовать типы с ограничениями. _>Более того иногда хочется проверки на переполнения например у целых чисел.
Такое нужно реализовывать не добавлением новых типов, а навешиванием на существующие специальных квалификаторов — это могли бы быть и инвариантные выражения, по типу assert, автоматически вычисляемые при выполнении.
_>Всё же вы видимо хотите ограничивать не компилятор, а программистов которые будут работать с этим кодом.
Разумеется, и себя в первую очередь. Я хочу, чтобы в любой спорной ситуации компилятор мог предупредить и меня, и любого другого. Но гибко управляемой системы контроля синтаксиса/семантики я ни у одного компилятора пока не видел.
_>Вам стоит использовать не C++, он явно преследует иные цели.
И что же мне использовать в ядре Windows, кроме C++, C и ассемблера?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Как бы поизящнее прикрутить к enum ограничение области видимости в версиях до C++11?
ЕМ>Я пока не придумал ничего лучшего, чем заворачивать enum в одноименный namespace, но тогда на имя типа приходится ссылаться конструкцией вида EnumType::EnumType, что выглядит как-то коряво.
помимо заворачивания в struct можно делать так, как в java
class MyEnum
{
public:
static const MyEnum Value1;
static const MyEnum Value2;
...
public:
//помимо основной работы по сокрытию значений из глобальной области видимости, можно наделать кучу (бес)полезных методов
std::string toString() const;
int toInt() const;
static MyEnum fromString(const std::string& str);
...
};
// минус конечно в том, что надо static значения выносить в cpp часть
const MyEnum MyEnum::Value1;
const MyEnum MyEnum::Value2;
Здравствуйте, sergii.p, Вы писали:
SP>помимо заворачивания в struct можно делать так, как в java
Это будет заворачиванием в класс, в чем разница?
Проблема в том, что enum в C++ изначально был перенесен криво — надо было сразу сделать разрешить конструкции вроде "enum public/private", а не тянуть двадцать с лишним лет, чтобы потом родить извращение в виде "enum struct/class".
конечно, дело вкуса, но мне первый вариант интуитивно понятнее. Хотя он и менее "в духе C++".
update: кстати, в такой ситуации очень легко запретить неявное преобразование в int и обратно. Можно переопределить operator| operator& для масок. В общем, чисто явовский подход: всё запретить, а потом долго мучиться, чтобы хоть что-то разрешить
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Разумеется, и себя в первую очередь. Я хочу, чтобы в любой спорной ситуации компилятор мог предупредить и меня, и любого другого. Но гибко управляемой системы контроля синтаксиса/семантики я ни у одного компилятора пока не видел.
Неужели только у вас одного такие проблемы возникали?
ЕМ>И что же мне использовать в ядре Windows, кроме C++, C и ассемблера?
Видимо то что компилирует в C/C++/assembler https://haxe.org/manual/types-enum-instance.html
Другой вопрос. Зачем вам понадобились enum-ы, да еще и изолированные. Без них никак?
Здравствуйте, kov_serg, Вы писали:
_>Неужели только у вас одного такие проблемы возникали?
Какие именно "такие"?
_>Зачем вам понадобились enum-ы, да еще и изолированные.
Для удобства и надежности. Типичный пример: есть сервер (в моем случае — драйвер ядра), есть клиент. При работе с сервером используются коды операций, режимов и т.п., которые наиболее естественно задавать перечислителями, эти коды часто передаются просто в параметрах запросов, вне структур. Если объявлять их обычными enum'ами — нужно приделывать к ним уникальные префиксы, а это выглядит коряво в языке, отродясь использующем квалификаторы областей видимости.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Для удобства и надежности. Типичный пример: есть сервер (в моем случае — драйвер ядра), есть клиент. При работе с сервером используются коды операций, режимов и т.п., которые наиболее естественно задавать перечислителями, эти коды часто передаются просто в параметрах запросов, вне структур. Если объявлять их обычными enum'ами — нужно приделывать к ним уникальные префиксы, а это выглядит коряво в языке, отродясь использующем квалификаторы областей видимости.
Зато С-подход от мнглинга не зависит.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, kov_serg, Вы писали:
_>Вот например функция sqrt ждёт положительные значения, asin значение из диапазона [-1..1]. Так что вполне можно использовать типы с ограничениями. Более того иногда хочется проверки на переполнения например у целых чисел.
Ну и как это будет выглядеть в коде?
вот у меня написано sqrt(b*b-4*a*c)
я так понимаю, что a, b, c -- обычные числа, соответственно и D = b*b-4*a*c тоже.
А в какой момент тип поменяется на "неотрицательный float"?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Для удобства и надежности. Типичный пример: есть сервер (в моем случае — драйвер ядра), есть клиент. При работе с сервером используются коды операций, режимов и т.п., которые наиболее естественно задавать перечислителями, эти коды часто передаются просто в параметрах запросов, вне структур. Если объявлять их обычными enum'ами — нужно приделывать к ним уникальные префиксы, а это выглядит коряво в языке, отродясь использующем квалификаторы областей видимости.
Я бы в таком месте предпочёл корявую надёжность изящным трюкам
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, kov_serg, Вы писали:
_>>Вот например функция sqrt ждёт положительные значения, asin значение из диапазона [-1..1]. Так что вполне можно использовать типы с ограничениями. Более того иногда хочется проверки на переполнения например у целых чисел.
E>Ну и как это будет выглядеть в коде? E>вот у меня написано sqrt(b*b-4*a*c) E>я так понимаю, что a, b, c -- обычные числа, соответственно и D = b*b-4*a*c тоже. E>А в какой момент тип поменяется на "неотрицательный float"?
В какой момент тип в шаблоне меняется на нужный? По мере надобности.
assume(b,a,c,D is real);
assume(D>=0);
D:=b*b-4*a*c;
return sqrt(D);
Здравствуйте, Евгений Музыченко, Вы писали:
_>>Зачем вам понадобились enum-ы, да еще и изолированные.
ЕМ>Для удобства и надежности. Типичный пример: есть сервер (в моем случае — драйвер ядра), есть клиент. При работе с сервером используются коды операций, режимов и т.п., которые наиболее естественно задавать перечислителями, эти коды часто передаются просто в параметрах запросов, вне структур. Если объявлять их обычными enum'ами — нужно приделывать к ним уникальные префиксы, а это выглядит коряво в языке, отродясь использующем квалификаторы областей видимости.
Подозреваю что для удобства вам помимо кодов операций еще и протокол обмена нужен (спецификация пакетов) что бы параметры операции передавать и ответы парсить.
Тут проще генераторы кода сделать из DSL что бы и клиентский и серверный код и спеки генерило. И пусть внутри выглядит как угодно.
Здравствуйте, kov_serg, Вы писали:
_>В какой момент тип в шаблоне меняется на нужный? По мере надобности. _>
_>assume(b,a,c,D is real);
_>assume(D>=0);
_>D:=b*b-4*a*c;
_>return sqrt(D);
_>
Зачем тут какие-то типы? Типы — это же про статические проверки, а не про RT
assert( D >= 0 ) достаточно, причём ВНУТРИ sqrt
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Зачем тут какие-то типы? Типы — это же про статические проверки, а не про RT E>assert( D >= 0 ) достаточно, причём ВНУТРИ sqrt
Это не статические проверки. Это уточнение типов по коду. Как pattern matching.
В зависимости от аргумета возможны разные алгоритмы расчета значения.
например maple
Да и в объявлении sqrt может быть уточнение что тип имеет ограничение.
Компилятор может по разному генерировать код в зависимости от уточнений, которыми вы можете ему помоч делать разные реализации.
Хороший пример язык halide, где можно указать как именно следует организовывать расписание исполнения.
По такому же принципу если вы отделяете алгоритм от расписания, типов данных, представления данных и граничных условий, то вы получаете новы степени свободы для синтеза и оптимизации исполняемого кода. Которые вы никогда не получите в C++ с его метапрограммированием и шаблонами.
_>Хороший пример язык halide, где можно указать как именно следует организовывать расписание исполнения. _>По такому же принципу если вы отделяете алгоритм от расписания, типов данных, представления данных и граничных условий, то вы получаете новы степени свободы для синтеза и оптимизации исполняемого кода. Которые вы никогда не получите в C++ с его метапрограммированием и шаблонами.
И при чём тут С/С++ и их система типов?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>И при чём тут С/С++ и их система типов?
При том в C++ вам не будет того что вы хотите ни в каком виде. Это просто инструмент со своими недостатками.
Или смеритесь с ними или используйте другой инструмент. С помощью C++ можно сколь угодно усложнить любую задачу и потом бороться с проблемами которые сами же создали.
Здравствуйте, Евгений Музыченко, Вы писали:
_>>Тут проще генераторы кода сделать из DSL что бы и клиентский и серверный код и спеки генерило.
ЕМ>Проще это становится, когда функций и типов данных набирается по нескольку десятков.
Обычно их сотни и более того они эволюционируют от версии к версии.