The question is more why do you have to explicitly make a static
member defined within the class const
or inline
, when you don't have to do that for a static
method, which is automatically made inline
when defined within the class. More broadly, the question is why does defining a method in a class make it inline
and why can't defining a static member in a class be treated as either inline
or like a file scope class scope global symbol like an out-of-line definition, instead of making it a compiler error.
When you define it static const
, it will optimise out the load and if you force it to load the value by making it volatile const
or taking the address of it, you will get a linker error because it never emits the symbol (clang will force you to define a static volatile const
out of line, but gcc won't). This is much unlike a const
at file scope.
What this says to me is that the default for a static
member is to not emit a symbol at all, rather than be inline
. const
allows the value to be optimised into the code as an immediate (which is why it actually lets you define it as const
, because if you didn't then you'd be left with no symbol and then references to that missing symbol) but still the compiler does not emit a symbol. But why is this? Why not just make it inline
by default, like a method, instead of emitting no symbol at all?
The only difference it has to a method is that the same definition can have multiple different values -- if you defined the class type in an anonymous namespace it would have static (local) linkage and then you could avoid the redefinition errors. Now, it would have multiple different states in the different translation units if it were included into the translation units but a method would not (it would have multiple definitions but those definitions would be identical). The same is true with non static linkage, where one of the definitions will be arbitrarily selected if the method is inline
, otherwise there will be a multiple definition error. With static
linkage, it also still prevents you from defining a static
member in the class without inline
, because it still would not emit a symbol.
Because it prevents you from defining a member (i.e. does not emit a symbol) when it would (static linkage) and wouldn't (extern linkage therefore linker error) have multiple value states, and when there would be a linker error (extern linkage) and when there wouldn't be a linker error (static linkage), it can't be to do with these properties.
So you have to ask why the intention of a member defined in a class would be out-of-line (i.e. like a regular file scope symbol), and the intention of a method defined in a class be inline
(i.e. emit symbol only if it is used in the translation unit, and select only one symbol in the comdat group to use). I mean, when a programmer defines a static method in a class, it's assumed to be the same method, but when they define a member, it could have many different values, which is an issue for comdat linkage, because you don't know which symbol it is going to select, and will be a silent logic error:
// file.cpp
#include <iostream>
struct c {
static inline int k = 3;
};
int func(){
std::cout << c::k;
return 0;
}
// main.cpp
#include <iostream>
struct c {
static inline int k = 4;
};
int main() {
std::cout << c::k; // prints 3
}
If it forces you to define it out of line, you will instead get a linker redefinition error, making it easier to diagnose. Admittedly, the same issue would arise if the method definitions were different, and the whole assumption here is that the class definition is supposed to be in a header file -- so why would the definition ever be different.
Making the static member definition in the class behave like an out-of-line definition would cause linker errors if you include it in multiple files, so it is not interpreted to be out-of-line by default, due to the annoyance. I do not however see any reason why it isn't made implicitly inline
like a static method defined in the class is though.
I do not think there is an answer other than 'that's how it is'. It's a bit like why you can't use static
to give a method static linkage (and it's an error, or the static
is ignored completely on -fpermissive
) but you can enclose it in an anonymous namespace to achieve that (and the anonymous namespace has to surround the definition and the declaration (so the class), not just the definition (or not just the declaration -- but that's impossible anyways because if the declaration is in an anonymous namespace then the definition has to be or it won't compile)). I haven't seen any such answer on SO as of yet.
static constexpr
is another alternative that could be used orenum
for constant that are really constants... – Synchromesh