Jump to content

    
Sign in to follow this  
ViKo

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

Recommended Posts

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

 

Edited by lamer0k
Забыл цитату

Share this post


Link to post
Share on other sites
4 часа назад, ViKo сказал:

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

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

 

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites
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> ; 

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites
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

 

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

Edited by lamer0k

Share this post


Link to post
Share on other sites

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

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 извлечь один (одинаковый у всех) член.
Или есть другой способ?

 

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites
В 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);

Ловко!

Share this post


Link to post
Share on other sites
Цитата

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

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

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

Цитата

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this