Поскольку возможно, что функция, объявленная как 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 во время компиляции, когда компилятор решает вместо этого обрабатывать ее как обычную функцию, когда она работала бы также во время компиляции? Есть ли известные распространенные подводные камни?
constexpr
функции будут вычисляться во время компиляции, когда все его аргументы являются константными выражениями, а результат также используется в константном выражении. Константное выражение может быть литералом (например, 42
), нетипичный аргумент шаблона (например, N
в template<class T, size_t N> class array;
), enum
объявление элемента (например, Blue
в enum Color { Red, Blue, Green };
объявлена другая переменная constexpr, и так далее.
Oни может быть оценивать, когда все его аргументы являются константными выражениями, а результат не используется в постоянном выражении, но это зависит от реализации.
Функция должна быть оценена во время компиляции, когда требуется постоянное выражение.
Самый простой способ гарантировать это — использовать 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;