AHTOXA 15 27 июня Опубликовано 27 июня · Жалоба 23 часа назад, Arlleex сказал: Ехех) Если б еще я детально понимал работу умных указателей)) Поэтому пока что оставил в заметках) Здесь совершенно не обязательно нужен умный указатель, подойдёт и обычный. Суть в том, что мы в интерфейсном классе объявляем указатель на класс-реализацию: // Foo.h class FooImpl; // forward-объявление класса реализации class Foo { public: Foo(); void somePublicFunc1(); void somePublicFunc2(); private: FooImpl* impl; } , а весь класс реализации целиком помещаем в *.cpp-файл: // Foo.cpp #include "Foo.h" struct FooImpl { void func1() // это у нас получается как бы приватная функция класса Foo, но её не видно в Foo.h { } int field1; // а это как бы приватные мемберы. int field2; }; void Foo::somePublicFunc1() { impl->field1++; // работаем с "приватным" членом impl->func1(); // вызываем "приватную" функцию } // конструктор Foo::Foo() { impl = new FooImpl; } Добавлю, что можно даже избежать использования динамической памяти, объявив в Foo массив достаточного размера, и расположив FooImpl поверх этого массива при помощи placement new. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 27 июня Опубликовано 27 июня · Жалоба 26 минут назад, AHTOXA сказал: Здесь совершенно не обязательно нужен умный указатель, подойдёт и обычный. Суть в том, что мы в интерфейсном классе объявляем указатель на класс-реализацию: Это уже гораздо понятнее)) Цитата Добавлю, что можно даже избежать использования динамической памяти, объявив в Foo массив достаточного размера, и расположив FooImpl поверх этого массива при помощи placement new. Это будет уже не очень безопасно и внешне стремновато, т.к. массив придется объявлять в классе Foo, т.е. в хедере, т.е. в интерфейсе, который мы как раз хотели максимально "свернуть" по содержимому. Ну можно статически аллоцировать из предопределенного пула FooImpl в конструкторе Foo. В общем, варианты есть, идея ясна, спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 27 июня Опубликовано 27 июня · Жалоба Как бы так красиво реализовать класс, который может изменить свой тип автоматически после уточнения? Ох как сказал. В чем, собственно, идея. У меня есть структуры enum Command { SPI_SEND_FLASH, SPI_SEND_RAM, SPI_SEND, SPI_FILL, SET_PIN, RESET_PIN, ... }; template<Command> struct Descriptor; template<> struct Descriptor<SPI_SEND_FLASH> { Descriptor() : cmd(SPI_SEND_FLASH) {} Command cmd : 3; bool dc : 1; u32 addr : 19, size : 9; } __attribute__((aligned(4))); template<> struct Descriptor<SPI_SEND_RAM> { Descriptor() : cmd(SPI_SEND_RAM) {} Command cmd : 3; bool dc : 1; u32 addr : 19, size : 9; } __attribute__((aligned(4))); template<> struct Descriptor<SPI_SEND> { ... } __attribute__((aligned(4))); template<> struct Descriptor<SPI_FILL> { ... } __attribute__((aligned(4))); ... У всех этих структур есть поле cmd, расположенное строго в одном месте. Я намерен реализовать кольцевой буфер, в который можно писать такие структуры, и читать их из него. Вот конкретно сейчас все идеально: в нужной точке исходника я просто пишу Descriptor<SPI_SEND> desc; и мало того, что создается интуитивно понятный конкретный экземпляр с нужными мне полями для данного типа дескриптора, так еще и автоматом заполняется его поле cmd. Очень удобно. Еще удобнее будет, если конструкторы каждой такой структуры снабдить параметрами-инициализаторами остальных членов. Для удобства чтения пока что опустил этот момент. И вот я имею этот самый заполненный нужными значениями desc. Мне его надо передать в функцию добавления в очередь. Эта функция будет принимать на вход некий "обобщенный" дескриптор, я пока что не знаю как именно он будет выглядеть, но надо будет сделать так, чтобы эта функция "молча" принимала такие вот структуры и добавляла их в программную очередь. Тупо как куски памяти. Окей, с этим еще более-менее понятно. Но встает проблема при чтении из очереди. Во-первых, при чтении куска памяти (структуры) мы пока что не знаем, какая конкретно эта структура. Мы можем определить это только пройдясь по некому switch-case по полю cmd. Ага - т.е. функция чтения дескрипторов из очереди будет возвращать, опять же, какой-то "универсальный/обобщенный" дескриптор. Я пока что описал его вот так struct GenericDescriptor { Command cmd : 3; // обязательная часть всех дескрипторов u32 : 29; }; Т.е. функция чтения из очереди будет возвращать мне GenericDescriptor. Как и любая обработка в run-time, где-то после чтения из очереди будет небольшой switch-case по cmd из этого дескриптора, чтобы, собственно, правильно вычитывать упакованные аргументы и предпринимать нужные действия. Самое интересное: я хочу, чтобы GenericDescriptor при вызове некого метода превратился "из дурачка" в "адекватного", т.е. в один из конкретных Descriptor<>, например, в Descriptor<SPI_SEND>. Как это нашкрябал я struct GenericDescriptor { ... template<Command T> auto &identify() { return *(reinterpret_cast<Descriptor<T> *>(this)); } }; Тот самый switch-case будет выглядеть так void QueueHandler() { GenericDescriptor desc = Queue.read(); switch (desc.cmd) { case SPI_SEND_FLASH: { auto concreteDesc = desc.identify(SPI_SEND_FLASH); // дальше работа с этим самым concreteDesc как с конкретным Descriptor<SPI_SEND_FLASH> break; } case SPI_SEND: { auto concreteDesc = desc.identify(SPI_SEND); // дальше работа с этим самым concreteDesc как с конкретным Descriptor<SPI_SEND> break; } ... } } Виден тот самый "костыль" - явное создание уточненного concreteDesc из обобщенного desc. Хотелось бы, чтобы этого присваивания не было вовсе. Есть ли способ написать функцию identify() так, чтобы при выходе из нее тип desc автоматически преобразовался в нужный? Т.е. в идеале GenericDescriptor desc; // сейчас desc имеет тип GenericDescriptor, т.е. нам видно только поле cmd desc.identify(SPI_SEND); // "переидентифицируем", типизируем заново этот дескриптор u32 addr = desc.addr; // здесь desc имеет вполне определенный Descriptor<SPI_SEND>, в котором есть поле addr ... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 29 июня Опубликовано 29 июня · Жалоба В классе можно как-то иметь вспомгательные члены данных, которые не будут занимать (распределять) память? Нечто похожее на #define. Enum как-то не очень подходит, т.к. мне надо в классе определить локальные постоянные выражения и константы, при этом эти константы будут использованы в определениях методов в классе и более ни для чего не нужны. Мне не надо, чтобы они занимали место в классе. Constexpr что-то не хочет в классе объявляться... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 29 июня Опубликовано 29 июня · Жалоба 16 minutes ago, Arlleex said: Constexpr что-то не хочет в классе объявляться... он и не должен )) поэтому использую Constexpr только в cpp/hpp файлах, вначале, вместо #define а внутри класса/структуры или пространства имен, увы, спасает лишь enum, например так: namespace stm32f1 { .... class Clock { public: .... struct PLL { using Source = enum { HSI, HSE }; .... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 79 30 июня Опубликовано 30 июня · Жалоба static constexpr int a = 40 внутри класса может иметь место. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 3 hours ago, EdgeAligned said: static constexpr int a = 40 внутри класса может иметь место. вспомнил, почему отказался от "внутри класса", он не поддерживает auto, которую очень часто вставляю по коду: static constexpr auto a = 40 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 79 30 июня Опубликовано 30 июня · Жалоба С другой стороны, в этом контексте auto не имеет большого смысла. auto хорошо, когда выводится возвращаемое значение функции или принимаемый в функицю параметр, или же присваивается небазовый тип, такой как итератор вектора, например auto it = vector.begin(); Хотя, сейчас попробовал - всё выводится, вот: Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 47 minutes ago, EdgeAligned said: С другой стороны, в этом контексте auto не имеет большого смысла. для меня auto - это не надо думать какой тут надо поставить тип, не надо где-то делать для него using (предпочитаю стандартные типы использоваться только в узкой области видимости, а если нет, то "именовать" их через using в обязательном порядке). AUTO - это просто написал и забыл. Предполагаю что компилятор умный, сам догадается чего от него хотят, и возможно его выбор в плане послед оптимизации будет куда практичнее ) Вангую хейт от "гуру оптимизации", но в моих задачах и проектах, где камень выбиратся с конским запасом, этот копеешный выиигрыш (и то не факт) вообще ни на что не повлияет ))) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 30 июня Опубликовано 30 июня · Жалоба 12 часов назад, Forger сказал: а внутри класса/структуры или пространства имен, увы, спасает лишь enum, например так: Ну да, видимо, единственный способ... 7 часов назад, EdgeAligned сказал: static constexpr int a = 40 внутри класса может иметь место. В таком случае компилятор считает такую запись эквивалентной static inline int a = 40, но это все равно не то, что мне нужно. Да, память не будет выделена под этот мембер в классе, но она все равно будет выделена для статического элемента, а мне и этого не нужно. Я просто хочу в классе иметь обычные именованные константы, наподобие дефайнов. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
EdgeAligned 79 30 июня Опубликовано 30 июня · Жалоба нет, я ж показал выше на картинке: у переменных a и b нет адреса локации. Вот еще раз. Вот куда помещается constexpr: вовнутрь ассемблерной инструкции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 30 июня Опубликовано 30 июня · Жалоба 18 минут назад, EdgeAligned сказал: нет, я ж показал выше на картинке: у переменных a и b нет адреса локации. Вот еще раз. Вот куда помещается constexpr: вовнутрь ассемблерной инструкции. Я опирался на cppreference, там было сказано про inline. Возможно, в Вашем случае произошла какая-то оптимизация)) Не могу сказать. Короче мне нужно некое выражение, не применяемое в первичном выражении (таком как объявление переменных). Enum подходит, но для задания констант в классе - весьма выглядит "странно")) constexpr при каких-то обстоятельствах, случайно, не может превратиться в обычный const? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 2 minutes ago, Arlleex said: constexpr при каких-то обстоятельствах, случайно, не может превратиться в обычный const? Не превратиться, constexpr это как раз прекрасная замена #define, хоть и не полноценная. Место в озу не занимают как const объекты. Можно делать даже constexpr функции (выражения), такие вычисляются при компиляции. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 169 30 июня Опубликовано 30 июня · Жалоба Ну если уж совсем придираться, то constexpr в плюсах - весьма темная тема со своей кучей подводных камней и я не сказал бы, что все так однозначно)) Я вот почитал https://habr.com/ru/articles/579490/ и не сказал бы, что constexpr такие же предсказуемые, как define)) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Forger 22 30 июня Опубликовано 30 июня · Жалоба 10 minutes ago, Arlleex said: Я вот почитал https://habr.com/ru/articles/579490/ и не сказал бы, что constexpr такие же предсказуемые, как define)) Да, однако дефайны ограничены, хотя и очень прозрачны и всем понятны. Если не лезть с constexpr в дебри и не пытаться "сову натянуть на глобус", то они вполне нормально работают вместо define. И главное - при желании очень легко и быстро превращаются в объекты и функции, перелопачивать код не нужно в отличие тех де дефайнов. кмк тут похоже действует привычное правило - не переборщить и не перемудрить )) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться