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

Нетиповой вариативный шаблон класса. Помогите написать.

14 часов назад, ViKo сказал:

А sizeof... здесь задействовать можно? Чтобы определить, с каким числом сравнивать? 

 

Добавлю еще как вариант, считать количество единиц в установленном значении :) Если количество единиц совпадает с количеством аргументом, то все пины уникальны.

struct Port 
{
  constexpr Port(int value): btn(value)
  {

  }
  const int btn;    
} ;

template<auto& ...args>
struct Pack
{  
   static constexpr size_t size =  (sizeof...(args))  ;
   static constexpr auto value = ((1 << args.btn) | ...) ;

   constexpr static std::size_t GetOnesCount(size_t val)
   {
       auto count = 0;

       for (auto n = val ; n != 0 ; count++)
       {
            n &= (n - 1) ;
       }
       return count ;
   }
   
   static constexpr bool unique  = (size == GetOnesCount(value)) ;     
} ;

constexpr Port P00{0} ;
constexpr Port P01{1} ;
constexpr Port P02{2} ;
constexpr Port P03{3} ;
constexpr Port P04{4} ;
constexpr Port P05{5} ;
constexpr Port P06{6} ;
constexpr Port P07{7} ;

using PortLits = Pack<P00, P01,P01,P04,P05,P06,P07> ;

//static_assert(PortLits::unique, "Беда, пины не разные") ;

int main()
{
  std::cout << PortLits::unique ; 

    return 0 ;
}

https://onlinegdb.com/HkJRyOL1U

 

Изменено пользователем lamer0k
Забыл цитату

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


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

static_assert(((1 << args.btn) | ...) == (1 << sizeof...(args) - 1), "Uh!");

 

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


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

4 часа назад, ViKo сказал:

static_assert(((1 << args.btn) | ...) == (1 << sizeof...(args) - 1), "Uh!");

 Так только последовательно заданные пины можно проверять. А если они не по порядку? 

 

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


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

Проверка нужна для целого порта, что все пины порта заданы. Вариативный шаблон в этом случае не нужен. Такой класс я уже написал. Порядок расположения пинов в аргументах шаблона не имеет значения, каждый определяется номером в структуре Pin.

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

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


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

4 минуты назад, ViKo сказал:

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

Я имею ввиду, зачем вам делать частный случай, если можно сделать сразу общий.

В вашем случае, например, можно задать только так 

Pack<P01, P02, P03, P04> ;

Но вот так уже нельзя

Pack<P01, P03, P04>

И  ваш ассерт сработает. Вопрос, почему?  Или вам прямо нужно, чтобы они только подряд шли?

9 минут назад, ViKo сказал:

Не буду же я задавать одинаковые пины в группе.

А если кто-то нечаянно сделает так:

constexpr Port CS{0} ;
constexpr Port DS{1} ;
constexpr Port MOSI{1} ; //ошибся 1 записал

Pack<CS, DS, MOSI> ; 

Ну или я не понимаю вашей задачи :)

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


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

Сейчас предполагаю 2 класса: Port на весь порт из 16 ножек и, например, Part на произвольное количество ножек порта. В первом будет конструктор - инициализатор. Там идёт просто запись в регистры. В Part будут операции чтение-модификация-запись во все регистры. Port выполняется в начале, при инициализации. Part - в процессе работы. 

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


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

Зачем выкинуть? Можно не использовать. 

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


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

9 часов назад, ViKo сказал:

Сейчас предполагаю 2 класса: Port на весь порт из 16 ножек и, например, Part на произвольное количество ножек порта.

Порт со списком пинов вообще по идее можно сгенерить на этапе компиляции, чтобы самому не писать руками, и ассерты для себя не вставлять:

//
template<std::size_t size, typename TPort, typename... Acc> 
struct CreateList
{
    using type =  typename CreateList<size - 1, TPort,  Port<TPort, size>, Acc...>::type ;  
} ;

template<typename TPort, typename... Acc> 
struct CreateList<0, TPort, Acc...>
{
    using type =   PinsPack<Port<TPort, 0>, Acc...> ;       
} ;

template<std::size_t size, typename T>
using GeneratePins = typename CreateList<size, T>::type ;

// Сгенерируем список пинов для портов 
using GpiobPort = GeneratePins<15, GPIOB> ; // PinsPack<Port<GPIOB, 0>, Port<GPIOB, 1>, Port<GPIOB, 2>, Port<GPIOB, 3>, 
                                            // Port<GPIOB, 4>, Port<GPIOB, 5>, Port<GPIOB, 6>, Port<GPIOB, 7>, Port<GPIOB, 8>,
                                            // Port<GPIOB, 9>, Port<GPIOB, 10>, Port<GPIOB, 11>, Port<GPIOB, 12>, Port<GPIOB, 13>, 
                                            // Port<GPIOB, 14>, Port<GPIOB, 15> >


// Тоже самое для порта А
using GpioaPort = GeneratePins<15, GPIOA> ; // PinsPack<Port<GPIOA, 0>, Port<GPIOA, 1>, Port<GPIOA, 2>, Port<GPIOA, 3>, 
                                            // Port<GPIOA, 4>, Port<GPIOA, 5>, Port<GPIOA, 6>, Port<GPIOA, 7>, Port<GPIOA, 8>, 
                                            // Port<GPIOA, 9>, Port<GPIOA, 10>, Port<GPIOA, 11>, Port<GPIOA, 12>, Port<GPIOA, 13>, 
                                            // Port<GPIOA, 14>, Port<GPIOA, 15> >

https://onlinegdb.com/BkPrIMK1L

 

С наступающим всех!!!!!

Изменено пользователем lamer0k

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


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

Продолжаю блудить.
Для класса из переменного количества ножек - ссылок структур

template <const Pin & ... PNN>
class Part
...

Чтобы задать нужный GPIO, хочу выбрать из структуры ножки член - имя порта.

Для полного набора ножек в порте было просто, использовал P00.name.

/*  Get GPIO structure pointer  */
	static constexpr volatile GPIO_TypeDef * getGpio() {
		return reinterpret_cast <volatile GPIO_TypeDef *>
	   (P00.name == GpioName::na ? GPIOA :
		P00.name == GpioName::nb ? GPIOB :
		P00.name == GpioName::nc ? GPIOC :
		P00.name == GpioName::nd ? GPIOD :
		P00.name == GpioName::ne ? GPIOE :
		// P00.name == GpioName::nf ? GPIOF :
		// P00.name == GpioName::ng ? GPIOG :
		GPIOH);
	}

У меня все члены структуры ножки - это перечисления с областью видимости:

/*! GPIO Name: A, B, C, D, E, F, G, H  */
enum struct GpioName { na, nb, nc, nd, ne, nf, ng, nh };

и т.п. для режимов, начального состояния.

 

А здесь есть только переменное количество параметров ... PNN.
Как же мне выбрать из первого аргумента (или из последнего, или даже из всех) это самое PNN.name? Пытаюсь теми самыми т.н. "свёртками" скомбинировать GpioName nn.

static constexpr GpioName Pname = GpioName((uint(PNN.name) | ...));
Но нужно приводить аргументы к uint, а затем результат к типу GpioName. Как-то дурно выглядит.

Здесь бы какую-то "пустую" операцию придумать, только бы из переменного набора PNN извлечь один (одинаковый у всех) член.
Или есть другой способ?

 

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


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

Кстати, с переходом на C++ Keil не выдаёт "C compiler listing" *.txt, а то, что выдаётся в *.lst, понять почти невозможно, а при высоком уровне оптимизации - совсем невозможно.

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


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

Еще такая штука. Вычисляю 64-битовое число. Если задать тип auto, компилятор даёт ошибку, если задать uint64_t - нормально компилируется.

Исправил. Задал в вычислении 1LL.

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


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

В 10.01.2020 в 13:12, ViKo сказал:

Как же мне выбрать из первого аргумента (или из последнего, или даже из всех) это самое PNN.name? Пытаюсь теми самыми т.н. "свёртками" скомбинировать GpioName nn.

static constexpr GpioName Pname = GpioName((uint(PNN.name) | ...));
Но нужно приводить аргументы к uint, а затем результат к типу GpioName. Как-то дурно выглядит.

Нашлось решение - оператор "запятая"! Заодно заменил имя PNN на PN, всегда с именами заморачиваюсь.
 

static constexpr GpioName name = (... , PN.name);

Ловко!

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


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

Цитата

В C++17 была добавлена новая возможность, именуемая выражениями сверт­ки (fold expressions) (см. краткое описание в разделе 4.2). Она применима ко всем бинарным операторам за исключением ., -> и [ ].

Это из книги Вандервуда и др. раздел 12.4.6. Выражения свертки.
А у меня запятая работает. Как?!

О, прочитал чуть ниже.

Цитата

Пустое раскрытие унарной свертки оператора запятой (,) дает выражение типа void.

В голове всего этого не удержать.

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


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

Еще одно замечание по Keil выдам. Симулятор не отрабатывает манипуляцию битами GPIO->BSRR. ODR остаётся неизменным. Раньше для STM32F103 симулятор был полнее.
Мелочь, пора бы уже знать. Наверное, знал да забыл.  

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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