Static Constant String (Class Member)

Static constant string (class member)

You have to define your static member outside the class definition and provide the initializer there.

First

// In a header file (if it is in a header file in your case)
class A {
private:
static const string RECTANGLE;
};

and then

// In one of the implementation files
const string A::RECTANGLE = "rectangle";

The syntax you were originally trying to use (initializer inside class definition) is only allowed with integral and enum types.


Starting from C++17 you have another option, which is quite similar to your original declaration: inline variables

// In a header file (if it is in a header file in your case)
class A {
private:
inline static const string RECTANGLE = "rectangle";
};

No additional definition is needed.

Why initilizing static const string member is not possible in class body

char is a fundamental type (ref 3.9.1 Fundamental types [basic.fundamental] in draft n4296 for C++14). It has neither constructor nor destructor and can be used in constexpr.

On the other hand, std::string is a class type. More exactly it is a specialization of basic_string, namely basic_string<char>. And the basic_string class has a lot of constructors, including the one taking a const char * parameter that is used in you code, but none is declared constexpr, so you cannot build a constexpr std::string. It makes sense, because the creation of a std::string is far from trivial and include dynamic allocation of a char array:

basic_string(const charT* s, const Allocator& a = Allocator());

... an allocated copy of
the array whose first element is pointed at by s

But IMHO the correct way would to declare an array:

class myClass
{
static constexpr const char S[] ="aa";
}
const char A::S[]; // do not forget to define the static element if it is later odr-used...

By the way, static data members shall be defined outside of their class definition if they are later odr used in the program. Implementations often allow integral constants or pointers to not be defined outside the class definition (anyway, no diagnostic is required for the one definition rule and undefined behaviour allows expected results), but strict C++ semantics do not.

Ref from n4296 draft for C++14 : 9.4.2 Static data members [class.static.data] §3

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class
definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignmentexpression
is a constant expression (5.20). A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. —end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.

How can you define const static std::string in header file?

One method would be to define a method that has a static variable inside of it.

For example:

class YourClass
{
public:

// Other stuff...

const std::string& GetString()
{
// Initialize the static variable
static std::string foo("bar");
return foo;
}

// Other stuff...
};

This would only initialize the static string once and each call to the function will return a constant reference to the variable. Useful for your purpose.

How to create a private static const string when using the pimpl idiom

#include <memory>

class Widget {
public:
Widget();
~Widget();
private:
class Impl;
std::unique_ptr<Impl> pimpl;
};

/*** cpp ***/

#include <string>

class Widget::Impl {
public:
static const std::string TEST;

Impl() { };
~Impl() { };
};

const std::string Widget::Impl::TEST = "test";

Widget::Widget() : pimpl(new Impl()) { }
Widget::~Widget() { }

You might want to consider making TEST a static function which returns a const std::string&. This will allow you to defined it inline.

Why can't I have public static const string S = stuff; in my Class?

A const object is always static.

is static const string member variable always initialized before used?

if we use the 2nd approach, is the variable ConstStrVal always initialized to "some_string_value" before it is actually used by any code in any case?

No

It depends on the value it's initialized to, and the order of initialization. ConstStrVal has a global constructor.

Consider adding another global object with a constructor:

static const std::string ConstStrVal2(ConstStrVal);

The order is not defined by the language, and ConstStrVal2's constructor may be called before ConstStrVal has been constructed.

The initialization order can vary for a number of reasons, but it's often specified by your toolchain. Altering the order of linked object files could (for example) change the order of your image's initialization and then the error would surface.

why is everybody using the 2nd approach?

many people use other approaches for very good reasons…

Which is the best approach, 2 or 3?

Number 3. You can also avoid multiple constructions like so:

class Demo {
public:
static const std::string& GetValue() {
// this is constructed exactly once, when the function is first called
static const std::string s("some_string_value");
return s;
}
};

caution: this is approach is still capable of the initialization problem seen in ConstStrVal2(ConstStrVal). however, you have more control over initialization order and it's an easier problem to solve portably when compared to objects with global constructors.

How to declare a static constant member variable of a class that involves some simple calculations?

Set the value of your static const member variables outside of the class declaration, using the following syntax.

// box.h
#pragma once

class box
{
public:
static const float x;
};

const float box::x = 1.0f;


Related Topics



Leave a reply



Submit