Q:

Why must const class members be static to be properly optimised?

Given:
class Foo {        const int x = 5; public: inline int get() { return x; } };
class Bar { static const int x = 5; public: inline int get() { return x; } };
int fn0(Foo& f) { return f.get(); }
int fn1(Bar& b) { return b.get(); }

Compiled output gives a memory fetch to read the value of x in fn0(), whereas adding static results the literal 5 being inlined in fn1().  The implication is that a caller to get() can be optimised as if it were using a constant in place of get() only when the integer constant is static.
I have more complex situations where static is not appropriate.  Derived classes initialise x to different values through the constructor; but to each of those classes x is a constant and those class methods could be optimised, as with the preceeding static case, if only get() evaluated to a true constant.
In fact, my commonest case is with the initialisation of references in the base class:
class Foo { int& x; public: Foo(int& init) : x(init) {} inline int get() { return x; } };
class Bar : public Foo { int m; public: Bar() : Foo(m) {} inline int getget() { return get(); };
int fn1(Bar& b) { return b.getget(); }

Here, if get() evaluated directly to Bar::m within getget() I would avoid a level of pointer indirection.  This will not be possible if x is static.
It's not clear to me why static is necessary to allow this optimisation.

A:

A static const int member initialized in-class is a true constant expression, that is, a compile-time constant.
A non-static const int member cannot be changed after it is initialized, but it is harder for the compiler to determine statically that it can only have one possible value. Note that a brace-or-equal-initializer for a non-static data member is only used if there is no mem-initializer for that member. This means that if for example you had this:
class Foo {
    const int x = 5;
  public:
    inline int get() { return x; }
    Foo() = default;
    Foo(int x) : x(x) {}
};

then Foo::x could be 5, if the default constructor is called, or it could be something else, if Foo::Foo(int) is called. Also consider what happens if the member is made public:
class Foo {
  public:
    const int x = 5;
    inline int get() { return x; }
};

Now it's possible to use aggregate initialization:
Foo f {42};
// f.x is 42

In the particular case of the Foo that you wrote, I believe it is true that Foo::x can only ever be 5, but it isn't as easy for the compiler to determine this as it would be if Foo::x were a static data member. Quite possibly the compiler implementers simply didn't bother to write such an optimization.

