C++17 Update:
static constexpr
variables are implicitly inline
so there's no external definition necessary.
Original question:
Let's say I have a list of constants such as
struct Cls {
static constexpr int N = 32;
static constexpr int M = 64;
};
This of course suggests that I add definitions for these to avoid ODR-usage issues that may occur so I need:
constexpr int Cls::N;
constexpr int Cls::M;
Why should I prefer this over
struct Cls {
enum : int {
N = 32,
M = 64
};
};
Which saves me of the ODR-usage headaches since N
and M
are more truly just constants and not objects in their own right (a bigger deal if this is header-only) and is shorter. I could explicitly specify the type enum : long long
or whatever if need be. What is the advantage of the first?
A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later.
const applies for variables, and prevents them from being modified in your code. constexpr tells the compiler that this expression results in a compile time constant value, so it can be used in places like array lengths, assigning to const variables, etc.
There will be no noticeable difference for integral constants when used like this. However, enum is actually better, because it is a true named constant. constexpr integral constant is an object which can be, for example, ODR-used - and that would result in linking errors.
The keyword constexpr was introduced in C++11 and improved in C++14. It means constant expression. Like const , it can be applied to variables: A compiler error is raised when any code attempts to modify the value. Unlike const , constexpr can also be applied to functions and class constructors.
One difference is that you can take the address of a static constexpr
but not of an enum
.
Another is that constexpr
isn't supported by older versions of the language (it was introduced in C++11).
I'd use enum
only if the values belong together. I'd also give the enum
a name that describes that relationship. I wouldn't use an enum
for defining unrelated constants.
Perhaps no advantage for your usage because you're just using simple fixed integer values.
But, [AFAIK] constexpr
can be more general as it allows initialization from anything that can be evaluated at compile time.
From type_traits
:
/// integral_constant template<typename _Tp, _Tp __v> struct integral_constant { static constexpr _Tp value = __v; typedef _Tp value_type; typedef integral_constant<_Tp, __v> type; constexpr operator value_type() const { return value; } #if __cplusplus > 201103L #define __cpp_lib_integral_constant_callable 201304 constexpr value_type operator()() const { return value; } #endif };
Thus, constexpr
has usage in metaprogramming.
The following is a bit rough.
If you had a function like:
constexpr unsigned
bitmask(int bitno)
{
return 1u << bitno;
}
You might find a usage such as:
constexpr unsigned BIT_0 = bitmask(0);
constexpr unsigned BIT_1 = bitmask(1);
The reason I would give you is that using enum { }
for constants is a misuse of the term enum
. You're not enumerating anything. It's a common misuse, granted; it has its practical advantages; but it's just kind of wrong. There should be a way to say "this is just a compile-time constant and nothing else". constexpr isn't that thing either, but it's closer than enum. And it's rightly the case that you can't enum floating-point values.
That being said - I often use enums for constants myself, when I want to protect myself against people writing something like void* ptr = &some_constant_value; std::cout << ptr;
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