Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why should I prefer static constexpr int in a class over enum for class-level integral constants?

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?

like image 535
Ryan Haining Avatar asked Feb 04 '16 22:02

Ryan Haining


People also ask

Why does constexpr need to be static?

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.

Should I use const or constexpr?

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.

Is enum a constexpr?

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.

What is constexpr in C ++ 11?

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.


3 Answers

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.

like image 152
emlai Avatar answered Oct 16 '22 18:10

emlai


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);
like image 37
Craig Estey Avatar answered Oct 16 '22 16:10

Craig Estey


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;

like image 2
einpoklum Avatar answered Oct 16 '22 18:10

einpoklum