- 1
bool ok = (state == 0) ? false : true;
Нашли или выдавили из себя код, который нельзя назвать нормальным, на который без улыбки не взглянешь? Не торопитесь его удалять или рефакторить, — запостите его на говнокод.ру, посмеёмся вместе!
−43
bool ok = (state == 0) ? false : true;
И это пишет человек, пишущий на плюсах уже много лет...
иначе некоторые компиляторы могут ругаться варнингами типа forcing int value to bool
ЗЫ ok = state != 0 не заработает без перегрузки соответствующего оператора.
http://liveworkspace.org/code/47a683ac91ec0b441cbd6ce3b0e2ea35
Так что будем считать, что != перегружено.
bool ok = static_cast<bool>(state);
:)
Код читается по-разному:
i) bool ok = state == 0; => положи в ok флаг соответствия state состоянию int 0
ii) bool ok = static_cast<bool>(state); => положи в ok битовое соответствие state.
Скажешь какую-нибудь ерунду не по делу :)
http://ideone.com/SCWMZ
Это не с++ way а какое-то байтоебство.
Так вот к чему я клоню - зачем применять каст там где он сроду не нужен, и можно написать простое, универсальное и понятное всем state == 0?
private:
int INTSTATE;
SomeEnumState ENUMSTATE;
public:
bool() {
return INTSTATE == 42 || ENUMSTATE == ESUCCESS;
}
};
bool b = state;
Поскольку bool() не explicit - все будет работать. Если же у нас с++11 и оператор explicit - то да, нужен каст. Но в таких случаях, имхо, лучше isSuccess(). Короче чем каст, и лучше показывает намерения.
Конечно, http://ideone.com/HLLIH
А еще можно было !(state ^ answer)
bool ok = state;
state - конечно же, объект, в котором есть operator bool () (на крайний говнослучай, не будем показывать пальцем - operator void *())
С++ way: double b = static_cast<double>(3)/static_cast<double>(2);
У вас написано: положи в ok state o.O причём они разных типов... Fail!
да, мсье ведь в курсе, что в с++ все три приведения типов эквивалентны:
Вот если bool ok = static_cast<bool>(state); То да, как раз так. Специально и придумали эти штуки, чтобы читать можно было, а не домысливать из "вселенского разума". Это ж один из немногих профитов C++.
bool x = z;
z приводится к типу bool
да, именно с помощью static_cast приводится к bool неявно
да, c-cast, записанный как (bool), для целочисленных типов будет приводиться компилятором как static_cast
опять искалеченные паскалем судьбы в православных разделах на гк??
4.12/1
[conv.bool] 4.12 Boolean conversions
An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.
очень запутанные вещи написаны в стандарте, очень
Когда в коде становится много всяких подобных abandon слов, приходится дочитывать то, что не написано. Это хорошо в художественной литературе, а не в коде.
Кто экономит на чистоте: тот или вор, или свинья. ;)
Я хочу создать один объект из другого и я точно знаю что, я уверен, что это возможно разрешить на стадии компиляции... И прочее бла, бла, бла.
Когда вы хотите что-то спросить у человека, вы подходите и заявляете: "Скажи-ка дядя, ты не видал здесь такого... с пупочкой?" или "Милостивый государь, не соблаговолите ли вы <...>"
Вот и разница между неявным и явным кастом.
Вы же не кастуете явно указатель на дочерний класс в указатель на родительский?
Или int в double в выражениях?
Так что неявный каст это не абсолютное зло.
Но не C++ way ;)
Неявный каст это из C. C++ более вежливый язык.
bool ok = state; Где здесь C++? :)
А вот где: bool ok = static_cast<bool>(state); :D
Если назначение оператора bool() очевидно - то каст не нужен, он понятности не добавит.
Если же назначение оператора bool() не очевидно - то такой оператор не нужен. И каст тоже.
это у него на /W3 на пустом месте вырастает ворнинг C4800: 'type' : forcing value to bool 'true' or 'false' (performance warning), в котором они официально заявляют, что все три указанных мной преобразования не спасут: уou can add "!=0" to the expression, which gives the expression type bool. Casting the expression to type bool will not disable the warning, which is by design.
просто ворнинг они не хотят убирать by design, вот и все
обычное дело для microsoft с ихними wontfix
А про is<Smth>(), конечно верно. static_cast говорит лишь о желании создать один тип из другого.
Я, может быть, чего-то недопонимаю, но ведь С++ как раз был изначально спроектирован как суперсет С с "вселенским разумом" который для нас behind the scenes реализует все типы и все базовые преобразования между классами (родитель-потомок).
Т.е. я понимаю там, надобность введения reinterpret_cast<>, чтобы реализовывать какие-то хаки/общаться со старым кодом. Но вот зачем отдельные static_cast и dynamic_cast, мне не понятно. Возможно я не учитываю какую-то деталь. По-моему, компилятор владеет достаточной информацией, чтобы самому понять, какой тип каста должен быть, а читающему код и так очевидно. С++ сам за меня реализует все VTable и внутреннюю реализацию и много прочей байды (в отличие от С) -- я об этом не должен задумываться. Так почему же С++ заставляет задумываться о "динамичности" каста? Возможно, конечно, тут что-то влияет на производительность интерпретации шаблонов.
Опять же, я могу ошибаться где-то.
C-style каст по своему определению (ибо это C-style) -- это reinterpret_cast для указателей, но static_cast для примитивов типа int <--> bool
Вместо же dynamic_cast и static_cast ввёл бы один общий cast<> с дополнительным аргументом-флагом: cast<Derived, NO_RUNTIME_CHECK> и cast<Derived> (синоним к cast<Derived, DO_RUNTIME_CHECK>)
Возражения?
очень даже не сомнительный - у меня вышло в 50 раз быстрее
http://pastebin.com/49RQKi0w
существует крайне мало случаев, когда без него не обойтись
обычно злоупотребление динамик кастом свидетельствует об архитектурной ошибке
а синтетический пример показывает, что 1 динамик каст в 50 раз медленнее 1 такого же статик каста
о чем флейм? что все касты заменить на c-style? этого не будет
ты в компайл-тайм не сможешь выловить 100% случаев совместимости типов и нахождения в нужном месте в иерархии - даже в линк тайме не сможешь, потому что всегда есть возможность написать dll, о которой никто ничего не знает на этапе компиляции твоего приложения
а делать пессимизации и все передачи указателей/ссылок на объекты просеивать через сито динамик-каста - нет нет нет
отдельные статик каст и динамик каст - первый приводит типы как считает нужным в компайл-тайме (и только в нем), второй лезет в иерархию классов и пытается там найти ответ в рантайме (быть может какой нибудь оптимизатор найдет в компайл-тайме, но на это рассчитывать нелепо)
при этом первый работает как бы с любыми типами, второй только со ссылками и указателями.
в режиме работы с ссылкой неуспешное приведение dynamic_cast сгенерирует исключение std::bad_cast, с указателями - нулевой указатель
неуспешное приведение static_cast приведет к ошибке компиляции
эти отличия не убеждают?
Нет, полная каша же, и я нигде так и не увидел оправдания ей. См. http://govnokod.ru/10569#comment144035
какое компилятор должен принимать решение, если я напишу (SomeType *)ptr?
в какое время он это обязан делать (компайл тайм, рантайм)? будет ли единство?
в какое время он это обязан делать (компайл тайм, рантайм)?
Как я написал выше в коменте, т.к. это С-style, то и кастовать в "идеальном С++" оно должно было бы как С, то есть как reinterpret_cast в общем случае, или как static_cast, если ptr имеет тип void*. То есть компайл-тайм.
Чтобы был райнтайм, в "идеальном С++", который проектировал бы я, использовался бы cast<> с дополнительным флагом по желанию, при котором можно отключить рантайм-проверку типов (для даункаста если хочется супер-производительности).
В остальном это забота компилятора определять, какой тип каста нужен.
Они "идеологически разными" вам кажутся только потому что вы привыкли к ним в С++. На самом деле они redundant и messy.
Два разных даже удобнее: сразу видно о чём речь. А так бы нам ещё во флаги всматриваться, да пытаться понять логику компилятора, где он какой каст вставил. И так тяжело бывает следить за неявным кастом, а по вашей логике ещё и за явным глаз да глаз. Неудобно ужасно. Неуважение к программисту какое-то.
Это всё равно, что команды распараллеливания в OpenMP: зашарашат, а потом думают: "Почему не работает?", а оказывается компилятор подтуповат, не уловил задумку клёвого прогера и "не так" распараллелил.
Компилятор должен быть как можно глупее. Только самое лобовое делать: ать-два, ать-два. Избавлять программиста нужно от необходимости выполнять монотонную работу, копипасты, например.
Есть такой, называется ассемблер.
> Избавлять программиста нужно от необходимости выполнять монотонную работу, копипасты, например.
И в ассемблере как раз есть макросы.
В том, что для отключения функции, не нужно вводить новый интерфейс. Напр. в D буфер в стеке по умолчанию инициализируется нулями. Если хочешь это отключить (что нужно редко, где-нибудь в цикле пару раз на всю программу) -- пиши "= void" в конце. Если бы D проектировал индус Страуструп, то он бы тут забацал два примитивных типа unsafe_byte_array и safe_byte_array и ещё бы заставлять кастовать между собой через ещё один интерфейс :) И его адепты бы восхваляли "очевидный и простой синтаксис".
>Два разных даже удобнее: сразу видно о чём речь
А зачем тебе нужно это видеть? Прематуре оптимизатион. Вот если окажется, что где-то есть даункаст в очевидный тип, и в этом боттлнек согласно профайлеру -- тогда задумывается и вставляй флаг, отключающий рантайм-проверку. В остальных случаях тип каста должен определяться самим компилятором, а не вручную программистом. Может быть ещё и методы скажете дёргать из VTable'а вручную? В чём тогда пойнт использовать С++, а не С?
>А так бы нам ещё во флаги всматриваться
Т..е., по вашему NO_RUNTIME_CHECK один раз в год -- менее очевидно, чем static_cast с размазанной семантикой?
>Компилятор должен быть как можно глупее
И поэтому нужно писать static_cast<bool>, хотя компилятору и так очевидно, что это статический каст? Тут совсем не нужно компилятор делать суперумным.
>Избавлять программиста нужно от необходимости выполнять монотонную работу
Да, вроде как писать static_cast и dynamic_cast там, где можно было бы написать просто cast (как единый притимив, в целом противопоставляемый С-style-касту).
>а по вашей логике ещё и за явным глаз да глаз
NO_RUNTIME_CHECK как раз кричит во весь код, что здесь оптимизация, отключили проверку: может быть креш, если что-то поменяем. При static_cast<WrongDerivedClass*> нихрена это не очевидно.
> NO_RUNTIME_CHECK
удачи, кастуй очевидные вещи в рантайме, зануляй в стеке буферы по умолчанию
> работа компилятора определять
ну так используй c-cast, в чем проблема, улучшатель
> с размазанной семантикой
> нихрена это не очевидно
если ты чего то не осилил - это твои личные проблемы
учить тебя тут уму разуму никто не собирается
курсы С++ для начинающих - в другом месте
Ну если тебе всё и всегда очевидно, то зачем тебе вообще типизация? Используй void*, гений.
а у тебя очевидный батхёрт от такой простой вещи
я тебе по секрету скажу, что даже static_cast в нормальном приложении должен быть серьезно оправданным случаем
>и никогда const_cast и dynamic_cast
Гы. А что же ты тут тогда лопочешь про оверхед в рантайме, если ты их почти не используешь? Типичный premature optimization головного мозга.
И я ничего не говорил о том, что кастование само по себе это ух как здорово.
>static_cast/reinterpret_cast
>ололо, как раз для наложения сишных структур на принятый из сети буфер
Сенсация: здесь специальный оператор кастования на уровне языка не нужен, обычный уже существующий C-style подойдёт. Не нужно вводить кучу примитивов на каждый чих -- тем более что сишные структуры как раз требует сишного подхода.
о том, почему один менее безопасный сишный каст превратился в три более безопасных ты почитаешь в открытых источниках
в этом топике я приводил пример
Это до тебя туго доходит. Ты опять говоришь мне о текущей реализации С++, а я говорю о том, как *следовало бы* сделать. Следовало бы reinterpret_cast, static_cast<T*>(void*) и static_cast<int> объединить с C-style-cast (повторяю для тупых -- не так, как оно реализовано сейчас в С++!), противопоставив C++style, class-based cast<>, где можно отключить рантайм-проверку для производительности. Здесь всё прекрасно очевидно, что компилятор вставит. Закрывая дыры Си, _cast-стайлы вводят собственные дыры, так что я не вижу особой причины радоваться.
Ну конечно если ты уже замусорил свою голову этим полупьяным бредом -- то оно тебе очевидно.
Я же просто говорю про изначально более чистый дизайн (по моему мнению).
В дизайне ПХП тоже много пьяного бреда, и я уверен, ты бы так же защищал ПХП, выучив все corner cases -- подменяя аргумент о хорошем дизайне аргументом о том, что ты осилил выучить этот дизайн -- следовательно, он хорош. Молодец.
Там где люди ставят каст, означает, что компилятор уже не в силах что-нибудь разрешить. Люди в здравом уме такой аншлаг, как static_cast<bool>(int) не пишут. Зачем они нужны трёх типов я уже здесь где-то написал: в какой момент возможно разрешить валидность кастовки.
Вам что сто типов каста нужно, раз вы флаги навешиваете?! Или вы плохо понимаете семантику слов static_ и dynamic_? Какая размазанность?
Заканчиваем балаган. Никакого супер-гавка.
Крестосрач считаем завершенным?
Так... Надо писать письмо в комитет по стандартизации, чтобы в новом C++ 2014 к олимпиаде в Сочи const_cast убрали.
В остальных 99.9% случаях const_cast юзают или по дурости и неумению пользоваться const'ами или для затыкания дыр во внешних либах, автор которых не осилил const'ы.
Сложно себе представить жизненную ситуацию, где внутри совместных интерфейсов может возникнут необходимость нарушить такой важный контракт.
Сами посудите.
Константность означает, что поставщик запрещает вам вмешиваться во внутреннюю структуру поставки, потому что это может вызвать нарушение согласованности. Если вы можете снять const, нарушить контракт, и при этом оставить поставщика и поставку в согласованном состоянии, значит либо вы знаете достаточно много о внутреннем устройстве поставщика, либо делаете это небезопасно из-за несогласованности контракта сдачи-приёмки.
И то, и другое -- это нарушение архитектуры. Нужен адаптер, врепер -- что угодно, что разрешит конфликт контракта, либо у вас нарушена инкапсуляция и нужно пересмотреть разбиение на классы.
Надеюсь, что библиотек, в интерфейсах которых не расставляют const уже не осталось.
> Существуют неизменные библиотеки для численного анализа.
У вас есть код этих библиотек? Если есть - садитесь и расставляйте const'ы. Ими вы ничего не испортите - ни самой библиотеки, ни софта который ей пользуется. За пару дней, думаю, управитесь.
Если кода нет, и из достоверных источников вам известно, что функция не портит аргументов (например так сказано в документации) - смело правьте ашку, дописывая в нее const.
Если же кода нет, и вы не уверены в том, что эти функции ничего не модифицируют - то какого #$% вы вообще используете const_cast!?
Гораздо быстрее в своей конкретной программе поставить два каста в нужном месте, где я уверен, что всё будет хорошо.
Какой смысл трогать библиотеку и заниматься чпоканием констов в сотне местах и просто тереть пальцы? Тем паче об исходный код, пусть они даже и есть. Я же его не править, а переиспользовать хочу.
Ну если либа под свободной лицензией, то почему бы не принести пользу сообществу, расставив в ней const'ы? Тогда таких библиотек станет еще меньше ;)
> Гораздо быстрее в своей конкретной программе поставить два каста в нужном месте, где я уверен, что всё будет хорошо.
Искренне надеюсь, что эта уверенность порождена анализом исходников, а не тестированием.
> Чтобы не нагружать и без того сложные вещи ещё и адаптерами
> поставить два каста
Два wrapper'а сильно усложнят программу?
Если написано, что данные по такому-то пришедшему указателю не меняются, то можно смело кастовать ссылку на внутренние данные в неконстантную для передачи в функцию.
Да, wrapper длиннее каста. Кроме того, каждый "новый" код -- это, собственно, и есть wrapp старого кода, который я переиспользую, в нечто новое.
Вы явно потеряли мысль: не исправить, а использовать то, что сделано.
Ну если этот код и есть высокоуровневая обертка над NR - пусть будут const_cast'ы ;) Лишь бы в прикладном коде их не было.
Хочу:
А ещё окромя static_cast и dynamic_cast хочу agree_cast, например:
Кстати, unconst(a) я делал на шаблонах, добротно получилось.[/вброс]
Та самая кошка!
Новый язык программирования:Do.
Пишешь Do, и компилятор компилирует это в прогамму :)
И правильно. В том 0.1% случаев когда он действительно нужен, а не притянут за уши к кривой архитектуре - его можно и написать.
dynamic_cast не всегда работает, поэтому придумали такой костыль.
Относительно кастов... static_cast -- разрешается на стадии компиляции. dynamic_cast -- разрешается во время исполнения, reinterpret_cast --разрешается никогда. const_cast -- для обхода запрета.
Да, и именно поэтому Страуструп при создании назвал его C with Classes. И поэтому ввёл совместимость на уровне исходного кода, хотя мог ввести просто ABI/API совместимость (как в C# сделали), избавив свой гениальный язык с "преимуществами ООП" от кучи кривых хаков, введённых в первую очередь потому, что С++ задумывался именно как суперсет С.
Это наследие от С.
Но у хороших С++ программистов типизация строгая. И они помидоры в огурцы не кладут.
если сущность из коробки предоставляет operator bool, нелепо везде писать static_cast<bool> для нее
если встроенный тип умеет себя кастить, надо этим пользоваться
если объект имеет operator bool (), надо этим пользоваться
code bloat нужен только для параноидального ПО, когда неумелые преобразования типов приводят к неожиданным для программиста ситуациям - ну так и С++ не подходящий для этого язык
однако в 99.99% программ общего назначения (а с++ как раз язык для таких программ) параноидальность не нужна - потому что увеличивается время разработки и ухудшается читаемость программ, а профита никакого - в элементарнейших ситуациях, таких как кастинг int к bool, даже начинающий программист понимает что происходит, это соответствует стандарту и даже не приводит к UB
не стоит уродовать возможности языка и тем более говорить что это всё С, а не С++
если почитать стандарт, во многих случаях комитет даже не парится с записью с-каста как static_cast - потому что это короче, проще и опытному программисту не доставляет проблем
пример с double d = 2.L/1 - это от лени дописать .L в любом из операндов? если надо делить две переменных, то достаточно тоже один операнд скастить
в пост призывается тарас с безопасными приведениями типов
Не согласен.
Полностью поддерживаю. В тех случаях где каст в бул очевиден - все понятно и без статик_каста. В тех случаях где каст не очевиден - каст не нужен ни в той ни в другой форме, и лучше применять другие средства.
BaseClass* B = new DerivedClass();
DerivedClass* A = (DerivedClass *)B;
http://govnokod.ru/10569#comment143947
а динамик каст нельзя заменить скобками, потому что скорее всего будет вызываться reinterpret (если компилятор не посчитает типы совместимыми), реже - статик
например,
или вопрос был зачем вместо c-cast определили static_cast/reinterpret_cast/const_cast?
http://ideone.com/M6mEG
static_cast сообщает больше о действии, чем c-cast и тем паче неявная кастовка типа.
Хороший тон, сообщать, по-возможности, полную информацию.
А то смотришь какую-нибудь передачу "совершенно секретно", а там говорят: "наука не может ответить на вопрос о том, почему период обращения Луны вокруг своей оси равен периоду обращения вокруг Земли". Это нехорошо.
Конечно, можно сказать, что лишний каст int к bool запутывает. Это, наверно, так. Но если state -- это пользовательский тип, который нужно привести к bool, например для тоже полиморфизма символа, то так писать и нужно. И мой пример со static_cast<double> как раз и был нацелен в примитивном виде на демонстрацию сложности ощущения неявного преобразования.
Не следует человека заставлять думать лишнего над тем, над чем он думать не должен.
Говорить нужно правду, только правду и всю правду.
А во-вторых, менять по ходу доказательства теоремы крест на звезду, а звезду на точку -- моветон. Так же и в коде менять один вид преобразования типа на другой в разных местах программы -- неприлично. Это не нанесёт вреда читающему, но осложнит понимание.
Хотите c-cast и неявный каст? Добро пожаловать в C! Короткий код -- высокая производительность.
C++ язык более читаемый с элементами обратной совместимости, чтобы определённое множество программистов быстрее смогло на нём создавать программы.
Наставили минусов и нафлудили.
Хехе.
PS: reinterpret_cast рулит!
Тут уже придумали: Вольт -- суперкаст!
Сам всё определяет своим супервзглядом, оптимизирует всё в суперскорость и отгоняет программистов супергавком!
Ну откуда будет существенный статический каст в Java, если все объекты наследуют одному, а самих объектов нет, есть только ссылки, которые всегда безболезненно одна в другую превращаются? Следить, чтобы объект в int не кастанули? Ну разве что... И reinterpret_cast в Java бессмысленный, потому что там не может возникнуть непонятной последовательности битов, там VM всё про всех знает.
Ну и зачем Java много кастов?
И так, я полагаю, во всех ваших "здравых" языках. Они просто не сталкиваются с ситуациями, с которыми можно столкнуться в C++, потому им и касты сложные не нужны.
Я повторяю мою мысль -- если бы я был Страуструпом и я бы сочинял суперсет Си, то я бы оставил семантику си-каста как он есть (как раз одно из тех мест, где совместимость с Си порушили) -- т.е. объединил бы static_cast<> и reinterpret_cast. А для классов заюзал бы один общий cast(). Остальное не наша забота.
Если уж на то пошло, почему С++ позволяет виртуальным методам вызываться динамически без указания большими буквами, что это рантайм-вызов? Вполне С++ way было бы вместо obj->foo() писать dynamic_call obj->foo()! А если не хочешь виртуально -- то вызывай так: static_call obj->foo()! Подумаешь, что во втором случае может крешануться, потому что вызван не на тот derived-class! В учебнике написано, что в целом такая конструкция более безопасная, чем устарелый, никчёмный C-style call. Гы.
> т.е. оверхед negligible
Вы видите взаимно-однозначное соответствие между этими двумя высказываниями?
Объясним третий раз.
static_cast -- это любое преобразование типа, которое нужно разрешить на этапе компиляции.
То есть, компилятор в определённом месте, где стоит static_cast должен вывести один тип из другого.
Это нужно, например, чтобы разрешить сложности с полиморфными символами на этапе компиляции. С тем же делением, нужно указать компилятору, что пришедшие два целых числа нужно трактовать как с плавающей точкой и вызвать нужную реализацию символа деления.
Бывают более экзотические случаи с необходимостью приведения типа в аргументах шаблонных функций/методов. Использование "даункаста" в static_cast нужно просто для того, чтобы на этапе компиляции воспользоваться преимуществами статической типизации и определить: а вообще возможно такое присвоение? А то вдруг я где ошибся, скомпилировал, думаю, что всё ок, а там два класса из разных иерархий.
dynamic_cast -- производит проверку совместимости контрактов в ран-тайм. То есть, уже недостаточно нам информации периода компиляции, чтобы решить этот вопрос. Программа может быть собрана из разных динамических библиотек, с разными контрактами и т.д. Но разрешимыми. И вот, в некоторых местах возникает необходимость перейти в расширенный контракт, чтобы переиспользовать код.
reinterpret_cast -- вообще ничего не проверяет. Он используется, если уже никакой информации получить не удаётся. Вам в каком-то MPI мессадже упали биты о.О И чё? Кто скажет вам, что это такое? Строка аль массив чисел, аль еШо чего-нибудь. Никто! Вам приходится надеяться, что данные пришли доверенные и не побились. Хеш сошёлся -- пошёл каст. Он говорит: думай об этих битах, как массиве целых! Ок! Но проблемо!
Три разных уровня возможно ошибки возникновения в коде: на этапе компиляции (можно проверить статическую типизацию), во время ран-тайм (можно выбросить исключение, если контракт неожиданный), во время исполнения, но без проверки (а потому что узнать неоткуда).
Ну так все эти ситуации в С++ -- от воспалённого мозга. Сами придумали проблему, сами решили. Потом сидят довольные -- какие мы умныя :)
Вот она -- сила... пенопласта... :)
Жесть, народ!
А ещё меня плющит от кода, набранного пропорциональным шрифтом