非依赖条件的条件 constexpr
Conditional constexpr on non-dependent condition
假设我有一个配置函数要由库的用户定义,它可能是也可能不是 constexpr
。
constexpr int iterations() { return 10; }
// Or maybe:
int iterations() { return std::atoi(std::getenv("ITERATIONS")); }
// I'm okay with requiring the constexpr version to be:
constexpr auto iterations() { return std::integral_constant<int, 10>{}; }
现在我有一个函数,它根据 iterations()
的值有不同的行为,但是如果 iterations
是,这个函数应该是 constexpr
,因为我希望用户是能够在 constexpr
中使用它,如果他们将库配置为允许它的话:
/*constexpr*/ std::uint32_t algorithm(std::uint32_t x) {
auto const iterations = ::iterations();
// For illustration purposes
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
如果 iterations()
是,我可以对 algorithm
做些什么来实现函数 constexpr
?简而言之,我想要 constexpr(constexpr(::iterations()))
.
这样的东西
请注意,“条件 constexpr
”通常取决于模板参数,如 in which case the constexpr
keyword can just be used, but in this case, I want the constexpr
to be conditional on something which is not a template parameter, but a statically known function. Marking algorithm
as constexpr
is a compilation error:
error: call to non-'constexpr' function 'bool iterations()'
I'm okay with requiring the constexpr version to be: ... std::integral_constant<int, 10>
因为您可以要求函数的 constexpr
版本具有不同的 return 类型,我们可以检测到这种特殊类型,并通过使用约束(C++20 的 requires
)。请注意,我们必须进一步将主体包裹在 if constexpr
中,因为编译器仍会检查函数的主体:
template <typename T>
constexpr bool is_integral_constant = false;
template <typename T, T value>
constexpr bool is_integral_constant<std::integral_constant<T, value>> = true;
constexpr std::uint32_t algorithm_impl(std::uint32_t x, int iterations) {
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())> {
if constexpr (is_integral_constant<decltype(::iterations())>) {
return ::algorithm_impl(x, ::iterations());
} else {
// Unreachable, but enough to convince the compiler that there is a
// constexpr friendly path through the function
return 0xDEADBEEF;
}
}
std::uint32_t algorithm(std::uint32_t x) {
return ::algorithm_impl(x, ::iterations());
}
从您的回答中汲取灵感,您可以使用概念来强加 iteration()
return 一个整数常数。
重要的是记住 algorithm()
ha 成为模板函数或概念 (requires
) 是行不通的,所以你可以强加一个未使用的默认模板参数
//VVVVVVVVVVVVVVVVVVVVVVVVVV <-- add this to activate `requires`
template <typename = void>
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())>
{ return ::algorithm_impl(x, ::iterations()); }
以下是你的例子的简化
template <typename T>
constexpr bool is_integral_constant = false;
template <typename T, T value>
constexpr bool is_integral_constant<std::integral_constant<T, value>> = true;
constexpr std::uint32_t algorithm_impl(std::uint32_t x, int iterations) {
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
template <typename = void>
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())>
{ return ::algorithm_impl(x, ::iterations()); }
std::uint32_t algorithm(std::uint32_t x) {
return ::algorithm_impl(x, ::iterations());
}
您可以通过确保存在 一些 组模板参数和函数参数来消除编译器诊断,即使 [=11] 对您的函数的调用是常量表达式=] 是 不是 常量表达式。例如:
template <bool True = true>
constexpr std::uint32_t algorithm(std::uint32_t x) {
if constexpr (True) {
auto const iterations = ::iterations();
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
} else {
return 0;
}
}
algorithm<false>(meow)
是常量表达式,只要 meow
是,所以编译器不会抱怨 (https://godbolt.org/z/GvE9ME)。
假设我有一个配置函数要由库的用户定义,它可能是也可能不是 constexpr
。
constexpr int iterations() { return 10; }
// Or maybe:
int iterations() { return std::atoi(std::getenv("ITERATIONS")); }
// I'm okay with requiring the constexpr version to be:
constexpr auto iterations() { return std::integral_constant<int, 10>{}; }
现在我有一个函数,它根据 iterations()
的值有不同的行为,但是如果 iterations
是,这个函数应该是 constexpr
,因为我希望用户是能够在 constexpr
中使用它,如果他们将库配置为允许它的话:
/*constexpr*/ std::uint32_t algorithm(std::uint32_t x) {
auto const iterations = ::iterations();
// For illustration purposes
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
如果 iterations()
是,我可以对 algorithm
做些什么来实现函数 constexpr
?简而言之,我想要 constexpr(constexpr(::iterations()))
.
请注意,“条件 constexpr
”通常取决于模板参数,如 constexpr
keyword can just be used, but in this case, I want the constexpr
to be conditional on something which is not a template parameter, but a statically known function. Marking algorithm
as constexpr
is a compilation error:
error: call to non-'constexpr' function 'bool iterations()'
I'm okay with requiring the constexpr version to be: ...
std::integral_constant<int, 10>
因为您可以要求函数的 constexpr
版本具有不同的 return 类型,我们可以检测到这种特殊类型,并通过使用约束(C++20 的 requires
)。请注意,我们必须进一步将主体包裹在 if constexpr
中,因为编译器仍会检查函数的主体:
template <typename T>
constexpr bool is_integral_constant = false;
template <typename T, T value>
constexpr bool is_integral_constant<std::integral_constant<T, value>> = true;
constexpr std::uint32_t algorithm_impl(std::uint32_t x, int iterations) {
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())> {
if constexpr (is_integral_constant<decltype(::iterations())>) {
return ::algorithm_impl(x, ::iterations());
} else {
// Unreachable, but enough to convince the compiler that there is a
// constexpr friendly path through the function
return 0xDEADBEEF;
}
}
std::uint32_t algorithm(std::uint32_t x) {
return ::algorithm_impl(x, ::iterations());
}
从您的回答中汲取灵感,您可以使用概念来强加 iteration()
return 一个整数常数。
重要的是记住 algorithm()
ha 成为模板函数或概念 (requires
) 是行不通的,所以你可以强加一个未使用的默认模板参数
//VVVVVVVVVVVVVVVVVVVVVVVVVV <-- add this to activate `requires`
template <typename = void>
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())>
{ return ::algorithm_impl(x, ::iterations()); }
以下是你的例子的简化
template <typename T>
constexpr bool is_integral_constant = false;
template <typename T, T value>
constexpr bool is_integral_constant<std::integral_constant<T, value>> = true;
constexpr std::uint32_t algorithm_impl(std::uint32_t x, int iterations) {
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
}
template <typename = void>
constexpr std::uint32_t algorithm(std::uint32_t x)
requires is_integral_constant<decltype(::iterations())>
{ return ::algorithm_impl(x, ::iterations()); }
std::uint32_t algorithm(std::uint32_t x) {
return ::algorithm_impl(x, ::iterations());
}
您可以通过确保存在 一些 组模板参数和函数参数来消除编译器诊断,即使 [=11] 对您的函数的调用是常量表达式=] 是 不是 常量表达式。例如:
template <bool True = true>
constexpr std::uint32_t algorithm(std::uint32_t x) {
if constexpr (True) {
auto const iterations = ::iterations();
for (int i = 0; i < iterations; ++i) {
x *= x;
}
return x;
} else {
return 0;
}
}
algorithm<false>(meow)
是常量表达式,只要 meow
是,所以编译器不会抱怨 (https://godbolt.org/z/GvE9ME)。