Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ 17 Metaprogramming recursive struct: enum or constexpr

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)
like image 591
alexpanter Avatar asked Oct 25 '20 19:10

alexpanter


Video Answer


1 Answers

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.

like image 87
Davis Herring Avatar answered Nov 14 '22 22:11

Davis Herring