Нашли или выдавили из себя код, который нельзя назвать нормальным,
на который без улыбки не взглянешь?
Не торопитесь его удалять или рефакторить, — запостите его на
говнокод.ру, посмеёмся вместе!
- это объявление лямбда-функции sidPathName без параметров с замыканием на локальные переменные по значению. Эта функция возвращает тип const char* const.
Поправте меня, если я сказал что-то не верно. Не довелось пока поработать с компилятором нового стандарта.
И так вопрос:
1)Что в данном случае const StringId?
2)Где говнокод? В 17ой строчке?
Подсистема локализации перекочевала из другого проекта с другим движком, где для этого дела была парочка дополнительных оптимизаций, но здесь пока не до них.
2) Я ещё сам до сих пор пытаюсь понять, насколько это говнокод. В данном конкретном случае можно было бы привычно обойтись выборкой нужной строки из локального статического массива констант, но несколько напрягает необходимость каждый раз отнимать единицу от значения из enum, чтобы получить индекс (0 там называется PATH_NOT_CHOSEN и валидным значением в данном случае не является, всё остальное идёт по порядку).
>1)typedef std::string StringId;
Вопрос не про данный конкретный проект, а про лямбды. Что в данном случае означает тип 'const StringId' с точки зрения семантики лямбд в С++?
const StringId sidPathName - объявление константной переменной, получающей возвращаемое лямбдой значение, ставшее результатом вызова, который можно видеть в той самой 17ой строчке.
Если точнее, в данном случае происходит неявная передача этого значения в конструктор std::string, но не суть.
Наличие лямбды справа от знака равенства семантику данного выражения меняет... ну, собственно, вообще никак не меняет.
Так это не вы говноавтор? Уф-ф, спасибо. А то я уж подумал, что таким гордятся.
По 0-му индексу можно засунуть фейковое значение ("" или NULL), если лень единицу отнимать. Но делать так не следует. Ведь никто не гарантирует, что значения энумов не изменятся. Лучше превратить лямбду в обычную именованную функцию. А ещё лучше -- вынести такие ресурсы во внешний файл данных.
Автор той самой системы локализаций - таки я. Внешний файл здесь не всегда катит (хотя, делай я этот проект с самого начала, с нуля и с вменяемыми сроками, наверняка нашёл бы такую возможность), т.к. те самые "строчки-пути" на самом деле заменяют числовые ид (энумы) реальных строчек. Как показала практика (два законченных проекта), строковые идентификаторы имеют кучу преимуществ перед энумами, и лишь пару недостатков, один из которых в оригинале отпимизирован (строки практически никогда реально не копируются и не сравниваются, т.к. StringId был совсем другим типом), а второй (невалидируемость компилятором) за более чем год активного пользования не создал сколь-нибудь заметных проблем.
Функцию сделал бы именованной, если бы она использовалась более чем в одном месте, в данном случае - это просто единичный кусок кода загрузки и разбора XML с некоторыми данными.
Лямбда по определению безымянная.
А присвоить её адрес переменной, сохранив оператор (), можно только двумя (известными мне) способами: через новое значение ключевого слова auto (т.к. нормального типа у неё нет, а тот, что есть - известен только компилятору), либо обернув в стыренную из буста std::function.
>т.к. нормального типа у лямбды нет, а тот, что есть - известен только компилятору
Разве лямбда не имеет тип функции или указателя на функцию? Если не имеет, то почему? Чем руководствовались создатели стандарта?
Скорее всего, тем, что реализовать лямбду, как обычную функцию, можно только при отсутствии замыкания. Если замыкание есть - то это уже не просто указатель на функцию, а объект с некоторым состоянием.
sidPathName, по сути, представляет из себя константу, зависящую от одного значения. Менять её в дальнейшем не нужно - только читать. Но если записать аналогичный код (со switch) без лямбды, её уже придётся делать неконстантной, т.к. в каждом case будет присваивание вместо return. Мелочь, конечно. Но если задаться целью обязательно сохранить const-корректность (о чём и речь), то выходы в старом стандарте - статические массивы (что не подходит для более сложных случаев), либо адские нечитабельные конструкции на тернарном операторе (типа моего предыдущего говнокода, но растущие пропорционально количеству вариантов).
Да. Это плод внезапного озарения, написанный ради двух целей:
1) сохранение константности (навеяно рефакторингом говнокода, в котором повсеместно применялся const_cast для передачи константного указателя в функцию, ожидающую неконстантного, при том что этой функции его неконстантность реально была нафиг не нужна);
2) чтобы самому увидеть, как же это извращение будет смотреться (результатом удовлетворён).
Здесь конст не теряется, зато кусок кода попадает достаточно далеко от единственного места своего применения.
А заинлайнить лямбду компилятор и сам додумается, если не тупой.
Во всяком случае, комбинация std::for_each с лямбдой на простом цикле по вектору 10-й студией в релизе разворачивается гораздо лучше, чем тот же цикл на итераторах. А то же самое через оператор [] вообще выдаёт войну и мир в дизасме.
Видимо, придётся смириться с тем фактом, что M$ более не поощряет написание кода, понятного даже школьнику.
Макрос ассерта тоже достался по наследству. А в релизе в случае ошибки любой невалидный ид развернётся в самого себя (в данном случае в пустую строчку).
Во всяком случае, это лучше, чем то, что будет в варианте со статическим массивом констант, если кто-то втихаря поменяет местами идентификаторы в enum.
>ид развернётся в самого себя (в данном случае в пустую строчку).
Тут всеж лучше падение программы с построением багрепорта, а не тихое замалчивание ошибки.
Не думаю, что конечному пользователю (игроку) понравится падение релизной версии программы по причине того, что кто-то потерял одну строчку в локализационной базе или опечатался в ид. Уж лучше немного хрени на экране с возможностью играть дальше.
А логи, баг-репорты и собственно ассерты есть в дебаге.
Да, кстати, в прошлых наших проектах было три конфигурации: debug, release и final. В релизе, благодаря включённым оптимизациям, было меньше тормозов, но логи и читы не отключались, а ассерты писали себя в лог, не прерывая выполнения. Финал же (с отключённым всем) собирался только для бета-тестов, окончательных релизов и т.п.
>Не думаю, что конечному пользователю (игроку) понравится падение релизной версии программы
Конечно ему больше понравятся глюки и не верные результаты работы программы, чем возможность получить исправленную версию продукта, в случае наличия ошибки. 😀
Целевой аудитории, состоящей из 50-летних дам, нажимающих кнопку "отмена" при виде надписи "подождите, распаковываются ресурсы" и не понимающих, какое старая видеокарта и малое количество памяти может иметь отношение к графическим глюкам - да. Больше. А вот претензий от издателя за внезапные креши будет куда меньше.
Лол
уже джва года http://8vmr.livejournal.com/6114.html
и при этом выглядит не как говно.
Эти новые фишечки похоронят С++ под горой нечитаемого символьного мусора.
Это Единичный тип (Unit Type) http://en.wikipedia.org/wiki/Unit_type. Тип с единственным значением, отсюда название. По-сути, обычный void, но пустая структура лучше моделирует такой тип.
ШТОЭТА? Плюсы скатываются в перл?
Раз уж получил в наследство от других говнокодеров проект под студию 2010 - грех не отыграться.
лямбды -- отличный способ писать нечитаемый говнокод, но например по linq, var и extension methods из C# ему далеко.
так что С++ еще некоторое время останется заповедником адекватов в море говнокодерства
Поржал.
В рядах смайликов пополняется.)
бля. чо они делают со стандартами, а?
А внизу (справа) это чьи-то яйца около рта? *ROFL*
А теперь внимание, вопрос знатокам: Чьи?
Счёт 7:0 в пользу телезрителей.
Скорее смайл обозначает охуевшего кодера с квадратными глазами, после того как он успешно прострелил себе ногу из С++рокетленчера.
Поправте меня, если я сказал что-то не верно. Не довелось пока поработать с компилятором нового стандарта.
И так вопрос:
1)Что в данном случае const StringId?
2)Где говнокод? В 17ой строчке?
typedef std::string StringId;
Подсистема локализации перекочевала из другого проекта с другим движком, где для этого дела была парочка дополнительных оптимизаций, но здесь пока не до них.
2) Я ещё сам до сих пор пытаюсь понять, насколько это говнокод. В данном конкретном случае можно было бы привычно обойтись выборкой нужной строки из локального статического массива констант, но несколько напрягает необходимость каждый раз отнимать единицу от значения из enum, чтобы получить индекс (0 там называется PATH_NOT_CHOSEN и валидным значением в данном случае не является, всё остальное идёт по порядку).
Вопрос не про данный конкретный проект, а про лямбды. Что в данном случае означает тип 'const StringId' с точки зрения семантики лямбд в С++?
Если точнее, в данном случае происходит неявная передача этого значения в конструктор std::string, но не суть.
Наличие лямбды справа от знака равенства семантику данного выражения меняет... ну, собственно, вообще никак не меняет.
Ваш кэп.
По 0-му индексу можно засунуть фейковое значение ("" или NULL), если лень единицу отнимать. Но делать так не следует. Ведь никто не гарантирует, что значения энумов не изменятся. Лучше превратить лямбду в обычную именованную функцию. А ещё лучше -- вынести такие ресурсы во внешний файл данных.
Функцию сделал бы именованной, если бы она использовалась более чем в одном месте, в данном случае - это просто единичный кусок кода загрузки и разбора XML с некоторыми данными.
Теперь ясно, что не прав. Лямбда-функция безымянная.
А присвоить её адрес переменной, сохранив оператор (), можно только двумя (известными мне) способами: через новое значение ключевого слова auto (т.к. нормального типа у неё нет, а тот, что есть - известен только компилятору), либо обернув в стыренную из буста std::function.
Ну это я и имел ввиду под именованной лямбдой. Некорректно выразился...
Разве лямбда не имеет тип функции или указателя на функцию? Если не имеет, то почему? Чем руководствовались создатели стандарта?
Поясните, пожалуйста, это высказывание.
"Заставь дурака Богу молиться, он и лоб разобьёт."
1) сохранение константности (навеяно рефакторингом говнокода, в котором повсеместно применялся const_cast для передачи константного указателя в функцию, ожидающую неконстантного, при том что этой функции его неконстантность реально была нафиг не нужна);
2) чтобы самому увидеть, как же это извращение будет смотреться (результатом удовлетворён).
где теряется конст, если делать вот так?
А заинлайнить лямбду компилятор и сам додумается, если не тупой.
Во всяком случае, комбинация std::for_each с лямбдой на простом цикле по вектору 10-й студией в релизе разворачивается гораздо лучше, чем тот же цикл на итераторах. А то же самое через оператор [] вообще выдаёт войну и мир в дизасме.
Видимо, придётся смириться с тем фактом, что M$ более не поощряет написание кода, понятного даже школьнику.
Ну и чем не подошёл?
Во всяком случае, это лучше, чем то, что будет в варианте со статическим массивом констант, если кто-то втихаря поменяет местами идентификаторы в enum.
Тут всеж лучше падение программы с построением багрепорта, а не тихое замалчивание ошибки.
А логи, баг-репорты и собственно ассерты есть в дебаге.
Да, кстати, в прошлых наших проектах было три конфигурации: debug, release и final. В релизе, благодаря включённым оптимизациям, было меньше тормозов, но логи и читы не отключались, а ассерты писали себя в лог, не прерывая выполнения. Финал же (с отключённым всем) собирался только для бета-тестов, окончательных релизов и т.п.
Конечно ему больше понравятся глюки и не верные результаты работы программы, чем возможность получить исправленную версию продукта, в случае наличия ошибки. 😀
ТарасБ фшоке.
уже джва года
http://8vmr.livejournal.com/6114.html
и при этом выглядит не как говно.
Эти новые фишечки похоронят С++ под горой нечитаемого символьного мусора.
>Эти новые фишечки похоронят С++ под горой нечитаемого символьного мусора.
В кои-то веки полностью соглашусь с мнением сего господина.
namespace boost {
namespace detail { struct none_helper{}; }
typedef int detail::none_helper::*none_t ;
} // namespace boost