Подтвердить что ты не робот

Когда функция constexpr получает оценку во время компиляции?

Так как возможно, что во время выполнения может быть вызвана функция, объявленная как constexpr, по каким критериям компилятор решает, следует ли вычислять ее во время компиляции или во время выполнения?

template<typename base_t, typename expo_t>
constexpr base_t POW(base_t base, expo_t expo)
{
    return (expo != 0 )? base * POW(base, expo -1) : 1;
}

int main(int argc, char** argv)
{
    int i = 0;
    std::cin >> i;

    std::cout << POW(i, 2) << std::endl;
    return 0;
}

В этом случае я неизвестно во время компиляции, что, вероятно, является причиной того, что компилятор рассматривает POW() как обычную функцию, которая вызывается во время выполнения. Однако эта динамика, насколько это может быть удобно, имеет некоторые непрактичные последствия. Например, может ли быть случай, когда я хотел бы, чтобы компилятор вычислил функцию constexpr во время компиляции, когда компилятор решает рассматривать его как нормальную функцию, а также, когда он работал бы во время компиляции? Существуют ли какие-либо известные ошибки?

4b9b3361

Ответ 1

constexpr функции будут оцениваться во время компиляции, когда все его аргументы являются постоянными выражениями, и результат также используется в постоянном выражении. Постоянное выражение может быть литералом (например, 42), аргументом шаблона не-типа (например, N in template<class T, size_t N> class array;), объявлением элемента enum (например, Blue в enum Color { Red, Blue, Green };), другая объявленная переменная constexpr и т.д.

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

Ответ 2

Функция должна быть оценена во время компиляции, когда требуется постоянное выражение.

Самый простой способ гарантировать это - использовать значение constexpr или std::integral_constant:

constexpr auto result = POW(i, 2); // this should not compile since i is not a constant expression
std::cout << result << std::endl;

или

std::cout << std::integral_constant<int, POW(i, 2)>::value << std::endl;

или

#define POW_C(base, power) (std::integral_constant<decltype(POW((base), (power)), POW((base), (power))>::value)

std::cout << POW_C(63, 2) << std::endl;

или

template<int base, int power>
struct POW_C {
  static constexpr int value = POW(base, power);
};

std::cout << POW_C<2, 63>::value << std::endl;