简体   繁体   中英

Why only integral or enum type can be initialised in a C++ class?

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 (ie 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...

Initialising of std::string requires some code to be executed in run time.

Initialising a pointer with string literal requires placing the string somewhere in the memory, also in run time.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM