Перейти к содержанию
    

Плавный переход C -> C++ под МК

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.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

26 минут назад, AHTOXA сказал:

Здесь совершенно не обязательно нужен умный указатель, подойдёт и обычный. Суть в том, что мы в интерфейсном классе объявляем указатель на класс-реализацию:

Это уже гораздо понятнее))

Цитата

Добавлю, что можно даже избежать использования динамической памяти, объявив в Foo массив достаточного размера, и расположив FooImpl поверх этого массива при помощи placement new.

Это будет уже не очень безопасно и внешне стремновато, т.к. массив придется объявлять в классе Foo, т.е. в хедере, т.е. в интерфейсе, который мы как раз хотели максимально "свернуть" по содержимому. Ну можно статически аллоцировать из предопределенного пула FooImpl в конструкторе Foo. В общем, варианты есть, идея ясна, спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как бы так красиво реализовать класс, который может изменить свой тип автоматически после уточнения? Ох как сказал.

В чем, собственно, идея.

У меня есть структуры

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
...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В классе можно как-то иметь вспомгательные члены данных, которые не будут занимать (распределять) память? Нечто похожее на #define.

Enum как-то не очень подходит, т.к. мне надо в классе определить локальные постоянные выражения и константы, при этом эти константы будут использованы в определениях методов в классе и более ни для чего не нужны. Мне не надо, чтобы они занимали место в классе. Constexpr что-то не хочет в классе объявляться...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 minutes ago, Arlleex said:

Constexpr что-то не хочет в классе объявляться...

он и не должен ))

поэтому использую Constexpr только в cpp/hpp файлах, вначале, вместо #define

а внутри класса/структуры или пространства имен, увы, спасает лишь enum, например так:

namespace stm32f1
{
....
	class Clock
	{
	public:

....
		struct PLL
		{
			using Source = enum { HSI, HSE };
....

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 hours ago, EdgeAligned said:

static constexpr int a = 40 внутри класса может иметь место.

вспомнил, почему отказался от "внутри класса", он не поддерживает auto, которую очень часто вставляю по коду:

static constexpr auto a = 40

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С другой стороны, в этом контексте auto не имеет большого смысла.
auto хорошо, когда выводится возвращаемое значение функции или принимаемый в функицю параметр, или же присваивается небазовый тип, такой как итератор вектора, например auto it = vector.begin();

Хотя, сейчас попробовал - всё выводится, вот:

 

Снимок экрана 2024-06-30 121854.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

47 minutes ago, EdgeAligned said:

С другой стороны, в этом контексте auto не имеет большого смысла.

 

для меня auto - это не надо думать какой тут надо поставить тип, не надо где-то делать для него using (предпочитаю стандартные типы использоваться только в узкой области видимости, а если нет, то "именовать" их через using в обязательном порядке).

AUTO - это просто написал и забыл. Предполагаю что компилятор умный, сам догадается чего от него хотят, и возможно его выбор в плане послед оптимизации будет куда практичнее )

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 часов назад, Forger сказал:

а внутри класса/структуры или пространства имен, увы, спасает лишь enum, например так:

Ну да, видимо, единственный способ...
 

7 часов назад, EdgeAligned сказал:

static constexpr int a = 40 внутри класса может иметь место.

В таком случае компилятор считает такую запись эквивалентной static inline int a = 40, но это все равно не то, что мне нужно. Да, память не будет выделена под этот мембер в классе, но она все равно будет выделена для статического элемента, а мне и этого не нужно. Я просто хочу в классе иметь обычные именованные константы, наподобие дефайнов.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

нет, я ж показал выше на картинке: у переменных a и b нет адреса локации.

Вот еще раз. Вот куда помещается constexpr: вовнутрь ассемблерной инструкции.

 

Снимок экрана 2024-06-30 162622.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

18 минут назад, EdgeAligned сказал:

нет, я ж показал выше на картинке: у переменных a и b нет адреса локации.

Вот еще раз. Вот куда помещается constexpr: вовнутрь ассемблерной инструкции.

 

Снимок экрана 2024-06-30 162622.jpg

Я опирался на cppreference, там было сказано про inline. Возможно, в Вашем случае произошла какая-то оптимизация)) Не могу сказать.

Короче мне нужно некое выражение, не применяемое в первичном выражении (таком как объявление переменных).

Enum подходит, но для задания констант в классе - весьма выглядит "странно"))

constexpr при каких-то обстоятельствах, случайно, не может превратиться в обычный const?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 minutes ago, Arlleex said:

constexpr при каких-то обстоятельствах, случайно, не может превратиться в обычный const?

Не превратиться, constexpr это как раз прекрасная замена #define, хоть и не полноценная. Место в озу не занимают как const объекты.

Можно делать даже constexpr функции (выражения), такие вычисляются при компиляции.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Я вот почитал https://habr.com/ru/articles/579490/ и не сказал бы, что constexpr такие же предсказуемые, как define))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 minutes ago, Arlleex said:

Я вот почитал https://habr.com/ru/articles/579490/ и не сказал бы, что constexpr такие же предсказуемые, как define))

Да, однако дефайны ограничены, хотя и очень прозрачны и всем понятны.

Если не лезть с constexpr в дебри и не пытаться "сову натянуть на глобус", то они вполне нормально работают вместо define.

И главное - при желании очень легко и быстро превращаются в объекты и функции, перелопачивать код не нужно в отличие тех де дефайнов.

кмк тут похоже действует привычное правило - не переборщить и не перемудрить ))

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...