All streams
Search
Write a publication
Pull to refresh
77
0
Send message

Такой общий вопрос к работе комитета. Недавно хотел я выяснить статус одного предложения. Я знаю номер предложения, я знаю ссылку на open-std. Но как понять, было ли оно принято или отклонено?


Судя по всему, чуть ли не единственный способ сейчас — спросить в "официальном" слаке. Ну или долго-долго листать все результаты всех встреч и искать там упоминания этого предложения, молясь, чтобы оно было там упомянуто с номером, а не просто как "Numbers TS".


Может быть, есть смысл завести хотя бы какую-нибудь табличку со статусами предложаний? Или может быть она уже есть, просто я не смог ее найти?

Во, вспомнил! Не extern, а export, и не Борланд, а EDG, и не выиграл, а проиграл.

Хммм, я видимо их с чем-то путал; какую-то похожую фишку вроде бы реализовывал только borland сто лет назад.
Спасибо, надо будет потыкать.


Хотя… если я правильно понял, это немного не то.
extern template по идее позволяет компилятору не инстанцировать один и тот же шаблон по нескольку раз в разных единицах компиляции, а рассчитывать на то, что он уже в одной из них создан.


Но на итоговый бинарник это вроде бы никак не влияет, одни и те же инстансы в нем не должны быть ни так, ни эдак; просто без extern template эта работа перекладывается на линкер.


Но как с помощью этого "объяснить" компилятору, что foo абсолютно идентичен foo — я не знаю.

Я особых проблем не вижу (хотя, опять-таки, компиляторов не пишу, а только вслух рассуждаю :).


Ну разные имена и разные — почему бы линкеру не создать два имени, которые ссылаются на одну функцию?


По-моему, проблемы могут быть только, если кто-то берет у метода адрес, а потом по адресу сравнивает методы на равенство. Это очень странный юз-кейс, но защититься вроде просто — если у метода берут адрес, то оставлять его уникальным.


Наверное, если код бинарный и библиотечный — тоже могуть быть проблемы, но шаблоны в бинарном виде вроде не экспортируют все равно.


С другой стороны, раз компиляторы не делают эту оптимизацию по-умолчанию, какие-то грабли на этом пути все-таки есть :)

Я имел в виду вот что — если шаблонный класс отнаследован от обычного, то теоретически компилятор мог бы сказать «да ну нахрен, перегружу-ка я все методы теневым образом, у меня ж тут шаблоны кругом, боюсь некорректного инстанцирования» и сделать копию тех же самых методов, но под видом перегрузки (даже если исходники невиртуальные).

Ну, я лично языковых поводов к такому поведению не вижу.
И для меня это как раз более сильное утверждение, чем факт, что один конкретный компилятор так не делает :)


А вообще вся переписка, если на нее поглядеть слегка со стороны, выглядит как «не используйте шаблоны, у меня от этого брат умер там какой-от треш и угар, и станет только хуже»

Ну это ж С++, все как обычно. Каждым инструментом нужно уметь пользоваться, больше силы — больше ответственности, стрелять себе в ногу и вот это вот все.

Не, ну если шаблоны инстанциированы в разных единицах компиляции, то почти очевидно, что и вложенные методы будут скопированы соответствующее число раз. Хотя странно, что компоновщик не оптимизирует это, для перегруженных методов обычных классов это же делается и таблица виртуальных методов одна (по крайней мере я так был всегда уверен). Хотя вот ниже пишут, что все-таки удаляет, но это видимо только полностью идентичных инстансов касается, а не вложенных методов.

Если шаблонный параметр одинаковый, то очевидно, а если он разный — то, видимо, не очень.


Я если что компиляторов не пишу и тут, скорее, теорезирую, чем твердые факты излагаю.


А точно ли при этом не создается новых копий и идет сугубо ссылка на методы базового класса?

Невиртуальный метод обычного класса — это просто свободная функция с неявным параметром this. Класс один — ну и метод тоже один. Тут я причин для появления копий не вижу.


А разные инстансы одного шаблона — разные классы, вот методы и получаются разными. Сливать их — это уже оптимизация, которой может и не быть.


Ну и я на практике вижу, что код резко худел, и по линкерным файлам тоже вижу, что копий не создается (хотя конкретный компилятор, конечно, не показатель).

Но если есть хотя бы один отличный параметр шаблона, то инстанциации имеют разный тип, и как автоматически удалять/сливать методы разных классов?

Если у них одинаковый машинный код, то почему бы не слить?
Например, метод в шаблонном классе, который шаблонные параметры вообще не использует.


Вроде бы в стандарте для функций нет правила, что "разные функции обязаны иметь разные адреса", которое есть для объектов.

Ну, если судить по буквальному значению аббревиатуры — то да, вы правы.
Но по сути эта идиома и словосочетание появилось в С++ благодаря деструкторам и подразумевает создание локального объекта.
Если нет деструкторов, то и пару fopen-fclose можно назвать RAII, но так, вроде бы, не говорят?


Вопрос терминологии, так что спорить не хочется.

Я, в целом, согласен, с парой не слишком существенных оговорок.


  • Конечно, почти все языки по Тьюрингу полны, а потому в каком-то смысле равномощны. Но лезть грязными лапами в неуправляемую память могут (или легко могут) не все, по факту остались — С, С++, Rust, D, Go (наверное?) и Swift какой-нибудь. Так что в этом смысле, да, Rust похож на С.
  • В Rust'e нет классов с конструкторами, а только структуры с прямой инициализацией полей; опять же, как в С.
  • Безопасная работа с памятью в Rust достигается все-таки не только силами стандартной библиотеки, а в первую очередь силами borrow checker'a, который статически проверяет заимствования. Стандартная библиотека — это уже надстройка для большего удобства.
  • Синтаксис у Rust и C разный. Вроде бы не сильно (хотя заметно), но во многом "синтаксис определяет сознание" и отделяет т.н. "идиоматические" конструкции от "чужеродных".

Вот этой самой "идиоматикой" Rust на С не очень похож, на мой взгляд. Скажем, на С невозможно сделать RAII, потому что нет деструкторов — поэтому подсчет ссылок может быть только ручной.
Всякой функциональщины в Rust тоже больше.


Ну и просто, как сказать? Философия иная, что ли. Безопасность на первом месте, а не "программист не должен ошибаться".
Поэтому от кода на Rust создается совсем другое ощущение в целом, что ли.


Отмажусь тоже, что я с вами не спорю, просто делаю ремарку, так сказать. Да на Rust я продакшен не пишу, так, играюсь. Поэтому все вышеперечисленное — эт просто мое мнение, которое я никому не навязываю :)

Довольно неожиданно. Я был полностью уверен, что уж одинаковый код точно должен быть в единственном варианте, как в случае с перегрузкой методов. И я не понял тогда, как с этим борются, в самых общих чертах?

Насколько я понимаю, тут сложность в том, что разные инстансы шаблонов могут быть созданы в разных единицах компиляции (т.е. вразных срр-файлах), потому что шаблоны всегда в хедерах, которые могут быть подключены в куче разных мест.
Поэтому чтобы провести такую оптимизацию, нужна т.н. "link-time code generation". Некоторые тулчейны вроде бы это умеют, например, у MSVC такой ключ есть.


Как еще борются — даже не знаю, если честно. Я лично просто одинаковый код из шаблонных классов выделяю в обычные, а из шаблонов только вызываю. Или наследую шаблонный класс от обычного. Пока что вроде хватало. Наверно, есть способы и получше.

Лично мне еще «Винландец в Нимриане» и Хэллаэнский цикл Смирнова вполне зашли. Вроде и попаданец, вроде и волшебство, но сюжет достаточно нестандартный.

Да я ж тоже не настаиваю :) Если вас все устраивает и вам удобно, то почему нет?
К тому же, опыта у вас заметно больше, чем у меня, вам наверняка виднее.


А Rust — штука хорошая, но на С он слабо похож, на мой взгляд, такое сравнение только мешает.

Ммм, поясните? Я человек, далекий от шаблонной магии, поэтому не все сходу понимаю, сорри.

Ну, суть шаблонов в том, что для каждого значения шаблонного параметра генерируется свой класс или метод. Даже если метод внутри себя этот параметр никак не использует; даже если метод получается совершенно одинаковый в каждом варианте шаблона.
Теоретически, компилятор мог бы и оптимизировать пачку таких методов в один, но на практике я такого не видел.
И получается, что размер кода пухнет просто на ровном месте.


Как же это он генерируется? Там данные из CMSIS SVD берутся, как я понял (видимо каким-то парсером, тоже пропреитарным), а сам-то код не генерируется, а пишется человеком с объемной головой.

Ну, главное ж что не надо все биты и все регистры руками заполнять. Ссылка на исходники парсера вроде в другой статье была. Или это другой парсер?

Боже, не хочу даже представлять тот день, когда мне придется еще и с внешней памятью на Миландрах возиться т_т


Я конечно не хочу сказать, что это вообще не нужно, просто значимость преувеличена. И тонкое место в таком случае имхо будет не в способе хранения класса Pin, а в используемых либах, качестве протоколов связи и изощрённости бизнес-логики

Тут не спорю, хотя плохо спроектированные шаблонные классы пустым конструктором способны отъедать очень много, совсем уж наплевательски относиться тоже нельзя.


В шаблонной магии автора, несмотря на ее объективную эффективность, меня ещё смущает ее недоступность для применения. Систему обычных классов любой программист слепит на раз-два, а всю вот эту вот красоту надо где-то брать, сам не напишешь. А негде, чтобы и лицензия МИТ, и под любые платформы.

Ну, учитывая, что код автора генерируется, а не руками пишется, вопрос сложности восприятия собственного библиотеки отходит на второй план.

Ну, косяки тоже нельзя со счетов сбрасывать. Я лично сталкивался с таким, что
а) Платы уже изготовлены в количестве 30 штук
б) На ней стоит контроллер с 4 Кб ОЗУ, потому что косяк, не заметили
в) Корпус у него такой, что ничего другого не поставить
г) Плату переделать уже не успеваем, придется жить с тем, что есть


Т.е. уметь экономить все-таки приходится, хотя как часто это пригодиться — заранее, конечно, не угадаешь.


Не стоит забывать и про кхм-кхм отечественные МК, где просто очень ограниченный модельный ряд. Хочется контроллер где ОЗУ или флеша побольше? А их нет. И не будет.

Расскажите, если найдете, мне тоже самому интересно, что же я такое предлагал.

Полагаю, что случаи у всех разные. Я разрабатываю в основном единичные изделия, в которых нет смысла экономить на спичках, поэтому могу себе позволить прошивки под сотню килобайт :)


А если серия крупная, то каждая копейка на счету. Каждый килобайт памяти тоже денег стоит, в итоге.

Вы не промахнулись комментарием случайно? Или я вопрос не понял.

А это и не надо. Просто структуру с идентификационными данными располагаем в определенной секции (.prod_id_data, например). А потом эту секцию располагаем сразу за векторами прерываний.

Все. Секция всегда помещается сразу за векторами. А размер таблицы векторов — уже дело компилятора.

Спасибо, такое мне в голову не приходило.
Жаль только, что линкер придется трогать.


Я пока что просто держу константный массив с инфо-строкой, а открывая прошивку просто ищу его поиском.


Про остальное — ну, вот именно этот момент меня и задерживает от перехода на плюсы. Грамотный аллокатор — штука не самая простая. К тому же довольно компромисная в части скорость-фрагментация. Очень не хочется терять такты и/или в нужный момент оказываться без необходимой памяти. Но еще раз — я согласен, это подход динозавров. Потому пока динозавры хоть кому-то нужны я предпочту «закатывать солнце вручную». Потом придется переучиваться, но это же потом…

Ну так аллокатор-то использовать совершенно необязательно; я ведь тоже без кучи живу и прекрасно себя чувствую.


Часть стандартной библиотеки использовать не получается — ну и пёс с ней, это в основном контейнеры. Если очень хочется — есть ETL, где все контейнеры фиксированной длины.


Но в целом С++ позволяет делать много всяких интересных вещей; можно, к примеру, на этапе компиляции заполнять массивы для табличной тригонометрии; делать более строгие проверки типов, чтобы случайно не сложить вольты с амперами.


Стандартная библиотека более богатая и с более приятным интерфейсом (местами); банально есть std::nth_element, чтобы медиану посчитать.


Last but not least — да, на С можно писать объектно-ориентированный код, но выглядит это отвратительно, столько работы, которую взял бы на себя плюсовый компилятор, приходится делать руками.


Конечно, С++ — это не страна сплошных медовых рек, но конкретно потребность в динамической памяти, имхо, далеко не главный минус.

Information

Rating
4,787-th
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Registered
Activity