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?
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);
I'm pretty sure I'm going to get flamed for this, but...
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;