Initialization of a Const Constant

It looks like I can create a static constant POD element, but not other types:

struct C { static const int a = 42; // OK static const string b = "hi"; // compile error }; 

Why?

+6
source share
3 answers

The syntax initializer in the class definition is only allowed with integral and enumerated types. For std::string it must be defined outside the class definition and initialized there.

 struct C { static const int a = 42; static const string b; }; const string C::b = "hi"; // in one of the .cpp files 

static members must be defined in one translation unit in order to fulfill one definition rule. If C ++ allows the definition below;

 struct C { static const string b = "hi"; }; 

b will be defined in each translation unit that includes the header file.

C ++ allows you to define const static data members of type integral or enumeration in a class declaration as abbreviated. The reason that const static members of other types cannot be defined is because nontrivial initialization is required (the constructor needs to be called).

+4
source

string not a primitive type (e.g. int ), but is a class.

To prohibit it is reasonable; static initialization occurs before main . And constructors can call all kinds of functions that may not be available during initialization.

+3
source

I will summarize the rules for direct class initialization in C ++ 98 vs C ++ 11:

The following code is illegal in C ++ 03, but works the same as you would expect in C ++ 11. In C ++ 11, you can think of it as initializers injected into each of the POD constructors, unless that constructor sets other meaning.

 struct POD { int integer = 42; float floating_point = 4.5f; std::string character_string = "Hello"; }; 

Creating fields that modify static members will break the code in both standards because static ensures that there will be only one copy of the variable, and therefore we must declare the members in exactly the same file, just as we will do with global variables using the aforementioned using the extern keyword.

 // This does not work struct POD { static int integer = 42; static float floating_point = 4.5f; static std::string character_string = "Hello"; }; int POD::integer = 42; float POD::floating_point = 4.5f; std::string POD::character_string = "Hello"; // This works struct POD { static int integer; static float floating_point; static std::string character_string; }; int POD::integer = 42; float POD::floating_point = 4.3f; std::string POD::character_string = "hello"; 

If we try to create them, constant constant members will create a new array of rules:

 struct POD { static const int integer = 42; // Always works static constexpr float floating_point = 4.5f; // Works in C++11 only. static const std::string character_string = "Hello"; // Does not work. constexpr static const std::string character_string = "Hello"; // Does not work (last checked in C++11) // Like some others have also mentioned, this works. static const std::string character_string; }; // In a sourcefile: const std::string POD::character_string = "Hello"; 

So, starting with C ++ 11, static constants of non-integer variables of trivial types are allowed. Strings, unfortunately, do not match the bill, so we cannot initialize constexpr std :: string even in C ++ 11.

Everything is not lost, although, as stated in this post , you can create string class functions as a string literal.

NB! Note that this is metaprogramming at best, if the object is declared as constexpr static inside the class, then as soon as you enter at run time, the object will not be found anywhere. I did not understand why, please feel free to comment on it.

 // literal string class, adapted from: http://en.cppreference.com/w/cpp/language/constexpr class conststr { const char * p; std::size_t sz; public: template<std::size_t N> constexpr conststr(const char(&a)[N]) : p(a), sz(N-1) {} // constexpr functions signal errors by throwing exceptions from operator ?: constexpr char operator[](std::size_t n) const { return n < sz ? p[n] : throw std::out_of_range(""); } constexpr std::size_t size() const { return sz; } constexpr bool operator==(conststr rhs) { return compare(rhs) == 0; } constexpr int compare(conststr rhs, int pos = 0) { return ( this->size() < rhs.size() ? -1 : ( this->size() > rhs.size() ? 1 : ( pos == this->size() ? 0 : ( (*this)[pos] < rhs[pos] ? -1 : ( (*this)[pos] > rhs[pos] ? 1 : compare(rhs, pos+1) ) ) ) ) ); } constexpr const char * c_str() const { return p; } }; 

Now you can declare conststr directly in your class:

 struct POD { static const int integer = 42; // Always works static constexpr float floating_point = 4.5f; // Works in C++11 only. static constexpr conststr character_string = "Hello"; // C++11 only, must be declared. }; int main() { POD pod; // Demonstrating properties. constexpr conststr val = "Hello"; static_assert(val == "Hello", "Ok, you don't see this."); static_assert(POD::character_string == val, "Ok"); //static_assert(POD::character_string == "Hi", "Not ok."); //static_assert(POD::character_string == "hello", "Not ok."); constexpr int compare = val.compare("Hello"); cout << compare << endl; const char * ch = val.c_str(); // OK, val.c_str() is substituted at compile time. cout << ch << endl; // OK cout << val.c_str() << endl; // Ok // Now a tricky one, I haven't figured out why this one does not work: // cout << POD::character_string.c_str() << endl; // This fails linking. // This works just fine. constexpr conststr temp = POD::character_string; cout << temp.c_str() << endl; } 
+1
source

Source: https://habr.com/ru/post/972370/


All Articles