For illustrative purposes, I'm showing two small, slightly different templated recursive definitions. One uses an enum
and the other uses static constexpr
to define a value.
I have inspected the output assembly from both programs, and they are exactly the same, and semantically they also appear the same.
I think constexpr
is maybe a bit more modern, but are there any differences between using enum
/static constexpr
, or are there any particular use cases where the difference would really matter?
// using enum
template<uint64_t N>
struct Sum {
enum : uint64_t { value = N + Sum<N - 1>::value };
};
template<>
struct Sum<0> {
enum : uint64_t { value = 1 };
};
// using static constexpr
template<uint64_t N>
struct Sum {
static constexpr uint64_t value = N + Sum<N - 1>::value;
};
template<>
struct Sum<0> {
static constexpr uint64_t value = 1;
};
Extracting value:
#define sum(n) (Sum<n>::value)
The most significant difference (since C++17 avoids the need for an out-of-class definition for the static data member) is that enumerators are instantiated along with the containing class, whereas static data members are instantiated only when needed. (Note, however, that MSVC, at least, doesn’t always properly defer them.)
This matters when you have several such constants and some of them make sense only for certain specializations. Errors in an initializer like T::maybe_exists
will not be triggered by instantiating the class in the static data member case.
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