Currently I am rewriting/extending my C++ utility library taking new C++11 features into account. One of the new additions is a template class which gives the maximum value of a set of numbers, hopefully at compile time.
template<typename T, T... Xs> class ConstMax
{
private:
template<typename... Ts> static constexpr T Max(Ts... xs);
template<typename Tx> static constexpr T Max(Tx x)
{
return x;
}
template<typename T1, typename T2, typename... Ts> static constexpr T Max(T1 x, T2 y, Ts... xs)
{
return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
}
public:
static const T Value = Max(Xs...);
};
An example use of this class:
int max = ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value;
Here another example which might make it harder to verify if ConstMax<...>::Value was actually evaluated during compile time:
template<typename... Ts> class Variant
{
public:
static const size_t MaxValueSize = ConstMax<size_t, sizeof(Ts)...>::Value;
};
Which results in max = 90
. I stepped trough this code using gdb and it seems there is no function call executed during the assignment of max.
My questions:
ConstMax<...>::Value
is always known at compile time?constexpr
functions/methods are evaluated at compile time?constexpr
are not necessarily evaluated during compile time, does the fact that Value
is defined as being static const
change anything about this or am I better off implementing this specific case as a recursive template class?Constant expressions. Certain forms of expressions, called constant expressions, can be evaluated at compile time. In const contexts, these are the only allowed expressions, and are always evaluated at compile time.
Difference between Run-time and Compile-time constantsA compile-time constant is a value that is computed at the compilation-time. Whereas, A runtime constant is a value that is computed only at the time when the program is running. 2.
The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time. Such variables and functions can then be used where only compile time constant expressions are allowed. constexpr implies const.
A const variable is a compile-time constant if its initializer is a constant expression. Because the initialization values of x and y are constant expressions, x and y are compile-time constants. This means x + y is also constant expression.
To check if an expression is constexpr
(i.e., constant expression) you could use std::integral_constant
type trait as follows:
#include <iostream>
#include <type_traits>
template<typename T, T... Xs> class ConstMax {
template<typename... Ts> static constexpr T Max(Ts... xs);
template<typename Tx> static constexpr T Max(Tx x) { return x;}
template<typename T1, typename T2, typename... Ts>
static constexpr T
Max(T1 x, T2 y, Ts... xs) {
return y > x ? Max<T2, Ts...>(y, xs...) : Max<T1, Ts...>(x, xs...);
}
public:
static const T Value = Max(Xs...);
};
int main() {
std::cout << std::integral_constant<int, ConstMax<int, 1, 8, 66, 32, 90, 12, 33>::Value>::value << std::endl;
}
Live Demo
If it's not constexpr
it will break the compilation process.
- Can I safely assume that ConstMax<...>::Value is always known at compile time?
Yes, since it's initialized with a constant expression. But I'd modify Value
to be constexpr
instead of just const
.
- Is there a way to check if constexpr functions/methods are evaluated at compile time?
Yes. Try using them in a constexpr
expression. If it works, they're being evaluated at compile time. If it fails to compile, then it's not being evaluated at compile time.
- I understand members/methods/functions defined as constexpr are not necessarily evaluated during compile time, does the fact that Value is defined as being static const change anything about this or am I better off implementing this specific case as a recursive template class?
If you use the members in a constant expression, you're forcing them to be evaluated at compile time. So if you cared, I'd just make sure to evaluate them in constant expressions (via constexpr
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With