lamer0k 0 29 декабря, 2019 Опубликовано 29 декабря, 2019 (изменено) · Жалоба 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 Изменено 30 декабря, 2019 пользователем lamer0k Забыл цитату Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 30 декабря, 2019 Опубликовано 30 декабря, 2019 · Жалоба static_assert(((1 << args.btn) | ...) == (1 << sizeof...(args) - 1), "Uh!"); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamer0k 0 30 декабря, 2019 Опубликовано 30 декабря, 2019 · Жалоба 4 часа назад, ViKo сказал: static_assert(((1 << args.btn) | ...) == (1 << sizeof...(args) - 1), "Uh!"); Так только последовательно заданные пины можно проверять. А если они не по порядку? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 31 декабря, 2019 Опубликовано 31 декабря, 2019 · Жалоба Проверка нужна для целого порта, что все пины порта заданы. Вариативный шаблон в этом случае не нужен. Такой класс я уже написал. Порядок расположения пинов в аргументах шаблона не имеет значения, каждый определяется номером в структуре Pin. А для работы с частью порта проверка количества пинов не нужна. Не буду же я задавать одинаковые пины в группе. А если вдруг (специально для демонстрации идиотизма) и задам, шаблон создаст класс со всеми заданными пинами. Лишних не прихватит, и нужных не забудет. Вот здесь нужен вариативный шаблон. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamer0k 0 31 декабря, 2019 Опубликовано 31 декабря, 2019 · Жалоба 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> ; Ну или я не понимаю вашей задачи :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 31 декабря, 2019 Опубликовано 31 декабря, 2019 · Жалоба Сейчас предполагаю 2 класса: Port на весь порт из 16 ножек и, например, Part на произвольное количество ножек порта. В первом будет конструктор - инициализатор. Там идёт просто запись в регистры. В Part будут операции чтение-модификация-запись во все регистры. Port выполняется в начале, при инициализации. Part - в процессе работы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 31 декабря, 2019 Опубликовано 31 декабря, 2019 · Жалоба А потом Part выкинуть за ненадобностью, и оставить только Pin :-) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 31 декабря, 2019 Опубликовано 31 декабря, 2019 · Жалоба Зачем выкинуть? Можно не использовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
lamer0k 0 31 декабря, 2019 Опубликовано 31 декабря, 2019 (изменено) · Жалоба 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 С наступающим всех!!!!! Изменено 31 декабря, 2019 пользователем lamer0k Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 января, 2020 Опубликовано 10 января, 2020 · Жалоба Продолжаю блудить. Для класса из переменного количества ножек - ссылок структур 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 извлечь один (одинаковый у всех) член. Или есть другой способ? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 января, 2020 Опубликовано 10 января, 2020 · Жалоба Кстати, с переходом на C++ Keil не выдаёт "C compiler listing" *.txt, а то, что выдаётся в *.lst, понять почти невозможно, а при высоком уровне оптимизации - совсем невозможно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 10 января, 2020 Опубликовано 10 января, 2020 · Жалоба Еще такая штука. Вычисляю 64-битовое число. Если задать тип auto, компилятор даёт ошибку, если задать uint64_t - нормально компилируется. Исправил. Задал в вычислении 1LL. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 января, 2020 Опубликовано 13 января, 2020 · Жалоба В 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); Ловко! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 января, 2020 Опубликовано 13 января, 2020 · Жалоба Цитата В C++17 была добавлена новая возможность, именуемая выражениями свертки (fold expressions) (см. краткое описание в разделе 4.2). Она применима ко всем бинарным операторам за исключением ., -> и [ ]. Это из книги Вандервуда и др. раздел 12.4.6. Выражения свертки. А у меня запятая работает. Как?! О, прочитал чуть ниже. Цитата Пустое раскрытие унарной свертки оператора запятой (,) дает выражение типа void. В голове всего этого не удержать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 13 января, 2020 Опубликовано 13 января, 2020 · Жалоба Еще одно замечание по Keil выдам. Симулятор не отрабатывает манипуляцию битами GPIO->BSRR. ODR остаётся неизменным. Раньше для STM32F103 симулятор был полнее. Мелочь, пора бы уже знать. Наверное, знал да забыл. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться