• Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: в общем придумал решение, как это все сделать красиво!
    1. Предполагаем, что пользователь ВСЕГДА ВВОДИТ ВЕРНЫЕ ЗНАЧЕНИЯ! В таком режиме код по ссылке вполне удачен. А далее делаем следующее.
    2. pin_config_t, объявлена так:
    /*
     * Структура конфигурации вывода.
     */
    struct __attribute__((packed)) pin_config_t {
        EC_PORT_NAME                port;               // Имя порта ( пример: EC_PORT_NAME::A ).
        EC_PORT_PIN_NAME            pin_name;           // Номер вывода ( пример: EC_PORT_PIN_NAME::PIN_0 ).
        EC_PIN_MODE                 mode;               // Режим вывода ( пример: EC_PIN_MODE::OUTPUT ).
        EC_PIN_OUTPUT_CFG           output_config;      // Режим выхода ( пример: EC_PIN_OUTPUT_CFG::NOT_USE ).
        EC_PIN_SPEED                speed;              // Скорость вывода ( пример: EC_PIN_SPEED::MEDIUM ).
        EC_PIN_PULL                 pull;               // Подтяжка вывода ( пример: EC_PIN_PULL::NO ).
        EC_PIN_AF                   af;                 // Альтернативная функция вывода ( пример: EC_PIN_AF::NOT_USE ).
        EC_LOCKED                   locked;             // Заблокировать ли настройку данного
                                                        // вывода во время инициализации global_port объекта ( пример EC_LOCKED::NOT_LOCKED ).
        EC_PIN_STATE_AFTER_INIT     state_after_init;   // Состояние на выходе после инициализации
                                                        // ( в случае, если вывод настроен как выход ).
                                                        // (пример EC_PIN_STATE_AFTER_INIT::NO_USE).
    };

    Мы добавляем вот такую оболочку!
    /**********************************************************************
     * Область template оболочек.
     **********************************************************************/
    template <EC_PORT_NAME              PORT,
              EC_PORT_PIN_NAME          PIN_NAME,
              EC_PIN_MODE               MODE,
              EC_PIN_OUTPUT_CFG         OUTPUT_CONFIG,
              EC_PIN_SPEED              SPEED,
              EC_PIN_PULL               PULL,
              EC_PIN_AF                 AF,
              EC_LOCKED                 LOCKED,
              EC_PIN_STATE_AFTER_INIT   STATE_AFTER_INIT>
    class pin_config_check_param : public pin_config_t {
    public:
        constexpr pin_config_check_param(): pin_config_t({
            .port               = PORT,
            .pin_name           = PIN_NAME,
            .mode               = MODE,
            .output_config      = OUTPUT_CONFIG,
            .speed              = SPEED,
            .pull               = PULL,
            .af                 = AF,
            .locked             = LOCKED,
            .state_after_init   = STATE_AFTER_INIT
        }) {
            if (PORT == EC_PORT_NAME::A) {
                static_assert(PORT >= EC_PORT_NAME::A && PORT <= EC_PORT_NAME::B, "pll_config<M> expects M between 2 and 63");
            };
        };
    };

    Условие набросал от балды. Тут может быть что угодно. Любая проверка параметров шаблона. Этим мы сможем гарантировать, что пользователь не делал чего-то типа (EC_PIN_MODE)(1221) и подобного.
    А в коде пользователя объявляем так:
    const pin_config_check_param<EC_PORT_NAME::A, EC_PORT_PIN_NAME::PIN_1, EC_PIN_MODE::OUTPUT, EC_PIN_OUTPUT_CFG::NO_USE, EC_PIN_SPEED::LOW, EC_PIN_PULL::UP, EC_PIN_AF::NO_USE, EC_LOCKED::LOCKED, EC_PIN_STATE_AFTER_INIT::NO_USE>led;

    Если нужен массив, то потом так:
    const constexpr pin_config_t ayplayer_global_port_pin_cfg_1[] = {
            led
    };

    Причем прошу заметить! Я создаю массив просто структур pin_config_t (обычные упакованные структуры из языка C (не CPP)). А внутрь помещаю созданную шаблоном. Причем они выглядят как абсолютно равнозначные.
    В сам объект я могу толкнуть при инициализации как указатель на массив упакованных структур, так и на созданные шаблоном экземпляр "структуры".
    const constexpr global_port ayplayer_global_port( ayplayer_global_port_pin_cfg_1, 1 );

    Конструктор объекта объявлен так:
    constexpr   global_port ( const pin_config_t* const pin_cfg_array, const uint32_t pin_count );

    Интересно вот только, почему это работает.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон:
    и вы используете GCC (и только его, как я понял, ничего для кейла и прочих друзей я пока не узрел). А GCC прекрасно умеет в #pragma once. Так вот вопрос, почему вы выбрали вариант с #ifndef abracadabra?
    когда-то просто где-то увидел, что делают так. Думал, иначе нельзя. Сейчас посмотрел, действительно очень удобно. Везде обновлю это. Спасибо.
    А насчет template сейчас пытаюсь выжать из компилятора все и кое что интересное написать. Как будет, отпишу сюда ссылкой на код (или просто скопирую). Ваш код, кстати говоря, сразу не стартанул. Ругался на
    typedef typename T cfg_type;
    . Но не суть. Сам подход уловил.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Можно подробнее про const? Вот библиотека с описанием: https://github.com/Vadimatorik/stm32f2_api
    Тут пока реализовано полностью только модуль port (в папке doc есть pdf с описанием логики работы модуля).
    Я выбрал constexpr, потому что не знаю, как иначе из заполненной пользователем структуры получить массив масок, которыми бы потом уже легко оперировал в реальном времени.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: Да. Будет просто const. Этого и добиваюсь. Только после того, как проверю все.
    У меня выбросить не выйдет. Т.к. частота плавает от 1 МГц до 120 МГц (stm32f205). И устройство местами от аккумулятора, а местами от USB. Так что критично.
    При том пишу сейчас библиотеку, которая полностью выкидывает HA или SPL. Пишу под конкретные нужды. Чтобы максимум производительности в ущерб памяти (ее всегда в моих- проектах 80% свободно).
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: моя цель проверить все параметры переданной пользователем в мою библиотеку структуры и составить на ее основе constexpr объект, который будет иметь const константы в private области и public методы для работы с ними (т.к. речь об программе для микроконтроллера, то объект будет лежать во flash памяти, обращения к нему из пользовательского кода). Сейчас все работает, но нельзя выкинуть ошибку, если что-то не так.
    За пример спасибо. Сейчас пробую привязать. Отпишу сюда о результате.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: я понимаю, но ведь должен быть какой-то способ выбросить предупреждение или указать на ошибку... Можно даже рассматривать стандарты выше 14-го. Может там что-то изменилось. Но все-равно, спасибо!
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон:
    constexpr const pll_cfg* rcc::pll_main_configuration_check ( const pll_cfg* const cfg, uint8_t count ) {
        // Проверяем все имеющиеся структуры конфигурации основного PLL.
        for ( int loop = 0; loop < count; loop++ ) {
            // Ошибка в одной из структур pll_cfg, параметр M.
            static_assert(( cfg[loop].m < 2 ) || ( cfg[loop].m > 63 ), "Structure has an invalid parameter M! M >= 2 and M <= 63!");

    Если я буду проверять внутри, то получу такую ошибку:
    error: non-constant condition for static assertion
    Что вполне оправдано. Ведь я, все-таки, использую счетчик.
    Мне бы просто найти альтернативу printf-у.
  • Как вывести из constexpr функции сообщение об ошибке и прервать компиляцию (C++1y; C++14)?

    @Vadimatorikda Автор вопроса
    Антон: у static_assert есть такая интересная проблема. Если я его напишу вместо throw, например:
    // Ошибка в одной из структур pll_cfg, параметр M.
    if ( ( cfg[loop].m < 2 ) || ( cfg[loop].m > 63 ) )
        static_assert(false, "Structure has an invalid parameter M! M >= 2 and M <= 63!");

    То оно будет вылетать всегда. Даже несмотря на то, что находится в теле условия. К тому же не ясно, как добавить в него еще и вывод переменной, на которой все упало.
  • Как с помощью constexpr C++11 создать const объект, который бы содержал внутри себя массив (const) указателей на объекты другого класса?

    @Vadimatorikda Автор вопроса
    Класс B так же должен быть создан const во flash еще на этапе компиляции. Массив указателей на объекты класса A должен быть внутри, так же во flash. Так же, в классе B нужно как-то записать в переменную size (произвольное название) размер созданного массива.