static_assert в конструкторе constexpr

Я ищу метод, чтобы определить, что заданное значение конструктора constexpr находится в допустимом диапазоне.

Код выглядит следующим образом:

class Timer0 {

constexpr uint16_t CalcPresecaler( uint32_t faktor )
{   
    uint16_t prescaler = faktor / 255;

    if ( prescaler <    1 ) return    1;  
    if ( prescaler <    8 ) return    8;  
    if ( prescaler <   64 ) return   64; 
    if ( prescaler <  256 ) return  256;
    return 1024;
}   

constexpr uint8_t PrescalerBits( uint16_t prescaler )
{   
    if ( prescaler == 1024 ) return 0b101;
    if ( prescaler ==  256 ) return 0b100;
    if ( prescaler ==   64 ) return 0b011;
    if ( prescaler ==    8 ) return 0b010;
    if ( prescaler ==    1 ) return 0b001;
    return 0b000; // should never happen
}  
    constexpr Timer0( const uint32_t sysclk, const uint32_t timerclk )
    {
        uint32_t faktor = sysclk/timerclk; 
        uint16_t prescaler = CalcPresecaler( faktor );
        uint8_t prescalerBits = PrescalerBits( prescaler );
        uint8_t compare = (faktor/prescaler)-1;
        static_assert( ???? ); << can not be used on function parameters
        OCR0=compare;
        TCCR0=0x08| prescalerBits;
        TIMSK=0x02;
    }
};
int main()
{
     Timer0 t0(  8000000, 10 );
}

Я уже прочитал C++11 - static_assert внутри функции constexpr?, но я могу не используйте throw, так как я нахожусь на встроенной цели avr, где gcc не включает исключения, даже если он используется здесь для проверки времени компиляции.

Любая идея, как определить во время компиляции, что значение compare не превышает заданное значение?


person Klaus    schedule 05.02.2021    source источник
comment
Может быть, вы могли бы сделать что-то незаконное? Возможно, reinterpret_cast или разыменование nullptr?   -  person user975989    schedule 05.02.2021
comment
@ user975989: и как это определить во время компиляции?   -  person Klaus    schedule 05.02.2021
comment
Почему не Timer0Impl<800000, 10> t0? В любом случае, это всегда будет время компиляции, верно?   -  person KamilCuk    schedule 05.02.2021
comment
Вы используете функцию constexpr с параметрами, значения которых неизвестны во время компиляции. Это намеренно?   -  person vahancho    schedule 05.02.2021
comment
if(!condition) *(int*)(nullptr)? Теперь я понимаю, что вы используете C++20, так что вы можете просто использовать consteval.   -  person user975989    schedule 05.02.2021
comment
@user975989 user975989 создание конструктора consteval по-прежнему сообщает, что значение «сравнить» не может использоваться в постоянном выражении.   -  person Klaus    schedule 05.02.2021
comment
@vahancho: какое значение неизвестно во время компиляции? У меня есть все значения во время компиляции... Не понимаю вашей точки зрения   -  person Klaus    schedule 05.02.2021
comment
Можете ли вы опубликовать минимально воспроизводимый пример? На данный момент есть недостающие функции.   -  person user975989    schedule 05.02.2021
comment
@ user975989: готово   -  person Klaus    schedule 05.02.2021
comment
Как насчет OCR0 и т. д.?   -  person user975989    schedule 05.02.2021
comment
@ user975989 avr target, это предопределенные имена регистров.   -  person Klaus    schedule 05.02.2021
comment
@Клаус, известны ли параметры функции const uint32_t sysclk и const uint32_t timerclk во время компиляции?   -  person vahancho    schedule 05.02.2021
comment
@Клаус, ты пробовал обычный assert? Он также создает ошибку времени компиляции, если используется в контексте constexpr.   -  person n314159    schedule 05.02.2021
comment
@ваханчо: Да. Конструктор вызывается с константами   -  person Klaus    schedule 06.02.2021


Ответы (2)


Поскольку вы не можете бросать, вы можете сделать что-то, что недопустимо в среде constexpr.

Например, если ваше условие таково, что prescalerBits != 0, вы можете сделать:

if (prescalerBits == 0)
    *(int*)nullptr = 0;

Что должно остановить любую оценку времени компиляции. Если вы беспокоитесь о вызове этой функции во время выполнения и получении разыменования нулевого указателя, вы можете защитить это условие с помощью std::is_constant_evaluated().

person user975989    schedule 05.02.2021
comment
есть ли шанс обнаружить и получить ошибку компиляции в случае, если мы не оцениваем константу? Невозможно использовать его ни в контексте constexpr, ни в static_assert. Таким образом, если пользователь lib вызывает контекст, отличный от constexpr, мы не получим никакой ошибки, даже если мы не получили доступ к nullptr. - person Klaus; 05.02.2021

Ваш код на самом деле не является самодостаточным, поэтому не совсем понятно, в чем проблема, поэтому мы решим аналогичную, но более простую проблему:

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

Первая неудобная правда C++:

В C++ нет аргументов функции constexpr.

Это сбивает с толку многих разработчиков, включая меня, но имеет смысл, когда вы понимаете, что это значит, но это отдельная длинная история...

Взломать/обойти это, чтобы использовать аргументы шаблона как способ иметь аргументы функции constexpr.

Простой пример:

constexpr void fn(const int val){
  // does not compile even when val is 47: fn(47).
  //static assert(val==47);
}

template<auto val>
constexpr void fn_cx(){
  // does  compile  when called with 47:  fn<47>()>
  static_assert(val==47);
}

теперь реализуем наш пример с прямоугольником:

class Rectangle{
    public:
    constexpr Rectangle(const int a, const int b): a_(a), b_(b){} 
    template<auto/*you can also use int here*/ a, auto b>
    static constexpr Rectangle MakeCx(){
        static_assert(a!=b,"square not allowed");
        return Rectangle(a,b);
    }
    constexpr int area() const{
        return a_*b_;
    }
    private:
    int a_;
    int b_;
};


int main()
{
    // ok
    constexpr auto rect = Rectangle::MakeCx<2,3>();
    // static_assert fails
    // constexpr auto square = Rectangle::MakeCx<2,2>();
    return rect.area();
}

Примечание: вы упоминаете, что используете некоторые предопределенные регистры, которые, очевидно, не могут быть записаны в конструкторе constexpr.

person NoSenseEtAl    schedule 11.02.2021