Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

enums

int

c++11

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;

}
like image 385
Giuseppe Pes Avatar asked Jan 17 '16 14:01

Giuseppe Pes


1 Answers

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

like image 110
Mats Petersson Avatar answered Nov 23 '22 18:11

Mats Petersson