constexpr uint8_t dizaine(uint8_t x) {
return ((x) / 10);
}
void setup() {
// put your setup code here, to run once:
uint8_t h = millis() & 0xff;
uint8_t heureDizaine = dizaine(h);
}
void loop() {
// put your main code here, to run repeatedly:
}
Почему он компилируется без ошибок? Ведь аргумент не является константой, известной на момент компиляции, что обязательно для constexpr?
Arduino IDE 1.8.19
плата - Arduino Mega
AVR Core v1.8.3
AI Overview
In C++,
constexpr functions can be used with non-constant (runtime) arguments, making them highly versatile for both compile-time optimization and runtime execution. While constexpr variables must be initialized with a constant expression, constexpr functions are designed to work in both contexts.
Here is a breakdown of how constexpr interacts with non-constant values:
constexpr Functions with Runtime Arguments
A constexpr function acts as a normal function at runtime if its arguments are not known at compile time.
Behavior: The function is evaluated at runtime, similar to a regular function.
Purpose: This allows you to write a single function that can be used for compile-time constants (e.g., template arguments) and also for variable data (e.g., user input).
Для полноты рассмотрения вопроса, я бы добавил, что в тех случаях, когда нужно однозначно гарантировать вычисления во время компиляции, следует использовать более сильный, чем constexpr спецификатор consteval. Это гарантирует вычисление на этапе компиляции или, в случае невозможности, приведёт к ошибке компиляции.
Также, если нужно обеспечить гарантированную инициализацию переменной на этапе компиляции, следует использовать constinit.
Главное отличие constinit от consteval в том, что в первом случае речь идёт о переменной (а не о константе). Она будет проинициализирована при компиляции, но потом никто не запрещает её изменять.
constinit и consteval доступны, начиная с С++20 (если склероз не изменяет).
Если сравнивать Си функцию с attribute((pure)) или attribute((const)) с функцией Си++, объявленной, как constexpr: одинаково ли компилятор понимает где и когда можно делать CSE (common subexpression elimination)? Например, пишет кто-то
a = func(1) + func(1) + func(1) + func(1);
Вопрос: свернет ли компилятор это в
a = 4 * func(1) // например
или будет честно вызывать функцию 4 раза подряд? Указывает ли constexpr компилятору как-то явно или не явно, что функция зависит только от аргументов?
Ну это вы просто в одном файле все сделали. Если бы вы fact() определили бы как extern, то вот тут бы самое интересное началось: компилятор не знает, что там внутри fact(). Вопрос, в том, что он сделает увидев a = fact(10) + fact(10).