I don't understand why C++ allows only integral types and enum (enum is an integral type too) to be defined within a class declaration. Whereas all other types, including float point types (i.e. double and float), have to be defined outside the class declaration. Clearly the must be a reason for this, but I can't figure it out.
Code example:
#include <iostream>
using namespace std;
struct Node {
static const int c = 0; // Legal Definition
static const long l = 0l; // Legal Definition
static const short s = 0; // Legal Definition
static const float f = 0.0f; // Illegal definition
static const string S = "Test"; // Illegal definition
static const string JOB_TYPE; // Legal declaration
static const float f; // Legal declaration
static const double d; // Legal declaration
};
const string Node::JOB_TYPE = "Test"; // correct definition
const float Node::f = 0.0f; // correct definition
const double Node::d = 0.0; // correct definition
int main() {
cout << Node::c << endl;
cout << Node::c << endl;
cout << Node::JOB_TYPE << endl;
cout << Node::f << endl;
}
The key reason here is that integral types (and enum
because inside the compiler these become integers of some sort) can be trivially replaced and used directly as constants.
In other words, struct S { static const int x = 42;}
, if the compiler sees S::x
, it can immediately replace it with the constant 42
in the generated code. The same does not (always) apply to float
, and certainly not for constructor-dependent types such as std::string
- the compiler can not allocate memory for std::string
without calling new
(or std::string::allocator
). So, for constants that have to be "constructed" and/or have more complex criteria for how they can be used (think of a processor that doesn't have hardware support for floating point - function calls to load and store floating point values, etc), the language can not dictate that it should be allowed to do that.
If you include the struct Node
declaration with static const std::string S = "test";
, how many places should the compiler store Node::S
in? Which one should it use, when it finally links your three translation units into one program - or should it use different ones? What happens then if you const_cast
the Node::S
and modify it? The latter is assuming you have an environment where this doesn't cause a crash, which is entirely plausible, and whilst that is undefined behaviour, I'm not sure the compiler should make it as weird as using different values in each translation unit in that case...
Edit:
As mentioned in the comments, C++11 does allow further types to be used in a similar way, so the restrictions are being relaxed as compiler and hardware technology is being improved. I doubt you'll ever be able to static const std::map<X, Y> a = { ... }
tho', as that is a rather complex data-type to construct...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With