What's the difference between static constexpr and static inline variables in C++17?

With C++17 we get inline variables.

One of the uses for them is to define constant fields in classes.

So what's the difference between these two constant definitions:

class MyClass {
static constexpr int myFirstVar = 10;
static const inline int mySecondVar = 100;
};

Of course constexpr makes myFirstVar implicitly inline.

What's the better choice here, to use constexpr or inline?

Note: when you don't need constness, then inline makes it easier. With constexpr you don't have that choice.

21544 次浏览

You don't have to specify an initializer for mySecondVar at the point of declaration. Nor is the initializer required to be constexpr itself.

This means that if we attempt to define myFirstVar like this:

class MyClass {
static constexpr int myFirstVar;
};


int MyClass::myFirstVar = 1;

Or like this:

#include <cstdlib>


class MyClass {
static constexpr int myFirstVar = rand();
};

It's ill-formed either way. constexpr semantics demand it and for a good reason.

The inline specifier approach allows us to include a static variable definition in the header itself, without the initializer being constexpr; or if the initializer is fairly complex it doesn't have to be in the class definition itself.

So this is a perfectly valid header in C++17:

#include <cstdlib>


class MyClass {
static const int mySecondVar;
};


inline const int MyClass::mySecondVar = rand();

The standard promises us that all translation units that include the header will see the same value for the variable, even though we won't know what it is until run-time.

It's mostly a library writers tool. Assume your library is header only. Then in the olden days, what were your options if you needed a static constant defined like this?

Well, you could have an object file shipped with your library. It will be compiled from a translation unit that contains just the constant definition. Now the library isn't header-only.

Or you could rely on inline functions instead. The inline variable effect can be achieved with the following:

class MyClass {
static inline int mySecondVar();
};


inline int MyClass::mySecondVar() {
static const int value = rand();
return value;
}

But it's hidden behind a wall of syntax, and masks what is essentially a constant, with a function call operator.