Static constant string (class member) - c++

I'd like to have a private static constant for a class (in this case a shape-factory).
I'd like to have something of the sort.
class A {
private:
static const string RECTANGLE = "rectangle";
}
Unfortunately I get all sorts of error from the C++ (g++) compiler, such as:
ISO C++ forbids initialization of
member ‘RECTANGLE’
invalid in-class initialization of static data member of non-integral type ‘std::string’
error: making ‘RECTANGLE’ static
This tells me that this sort of member design is not compliant with the standard. How do you have a private literal constant (or perhaps public) without having to use a #define directive (I want to avoid the uglyness of data globality!)
Any help is appreciated.

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.

In C++11 you can do now:
class A {
private:
static constexpr const char* STRING = "some useful string constant";
};

Inside class definitions you can only declare static members. They have to be defined outside of the class. For compile-time integral constants the standard makes the exception that you can "initialize" members. It's still not a definition, though. Taking the address would not work without definition, for example.
I'd like to mention that I don't see the benefit of using std::string over const char[] for constants. std::string is nice and all but it requires dynamic initialization. So, if you write something like
const std::string foo = "hello";
at namespace scope the constructor of foo will be run right before execution of main starts and this constructor will create a copy of the constant "hello" in the heap memory. Unless you really need RECTANGLE to be a std::string you could just as well write
// class definition with incomplete static member could be in a header file
class A {
static const char RECTANGLE[];
};
// this needs to be placed in a single translation unit only
const char A::RECTANGLE[] = "rectangle";
There! No heap allocation, no copying, no dynamic initialization.
Cheers, s.

In C++ 17 you can use inline variables:
class A {
private:
static inline const std::string my_string = "some useful string constant";
};
Note that this is different from abyss.7's answer: This one defines an actual std::string object, not a const char*

This is just extra information, but if you really want the string in a header file, try something like:
class foo
{
public:
static const std::string& RECTANGLE(void)
{
static const std::string str = "rectangle";
return str;
}
};
Though I doubt that's recommended.

The class static variables can be declared in the header but must be defined in a .cpp file. This is because there can be only one instance of a static variable and the compiler can't decide in which generated object file to put it so you have to make the decision, instead.
To keep the definition of a static value with the declaration in C++11
a nested static structure can be used. In this case the static member
is a structure and has to be defined in a .cpp file, but the values
are in the header.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Instead of initializing individual members the whole static structure is initialized in .cpp:
A::_Shapes A::shape;
The values are accessed with
A::shape.RECTANGLE;
or -- since the members are private and are meant to be used only from A -- with
shape.RECTANGLE;
Note that this solution still suffers from the problem of the order of
initialization of the static variables. When a static value is used to
initialize another static variable, the first may not be initialized,
yet.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In this case the static variable headers will contain either { "" }
or { ".h", ".hpp" }, depending on the order of initialization created by the linker.
As mentioned by #abyss.7 you could also use constexpr if the value of the variable can be computed at compile time. But if you declare your strings with static constexpr const char* and your program uses std::string otherwise there will be an overhead because a new std::string object will be created every time you use such a constant:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}

To use that in-class initialization
syntax, the constant must be a static
const of integral or enumeration type
initialized by a constant expression.
This is the restriction. Hence, in this case you need to define variable outside the class. refer answwer from #AndreyT

possible just do:
static const std::string RECTANGLE() const {
return "rectangle";
}
or
#define RECTANGLE "rectangle"

You can either go for the const char* solution mentioned above, but then if you need string all the time, you're going to have a lot of overhead.
On the other hand, static string needs dynamic initialization, thus if you want to use its value during another global/static variable's initialization, you might hit the problem of initialization order. To avoid that, the cheapest thing is accessing the static string object through a getter, which checks if your object is initialized or not.
//in a header
class A{
static string s;
public:
static string getS();
};
//in implementation
string A::s;
namespace{
bool init_A_s(){
A::s = string("foo");
return true;
}
bool A_s_initialized = init_A_s();
}
string A::getS(){
if (!A_s_initialized)
A_s_initialized = init_A_s();
return s;
}
Remember to only use A::getS(). Because any threading can only started by main(), and A_s_initialized is initialized before main(), you don't need locks even in a multithreaded environment. A_s_initialized is 0 by default (before the dynamic initialization), so if you use getS() before s is initialized, you call the init function safely.
Btw, in the answer above: "static const std::string RECTANGLE() const" , static functions cannot be const because they cannot change the state if any object anyway (there is no this pointer).

The current standard only allows such initialization for static constant integral types. So you need to do as AndreyT explained. However, that will be available in the next standard through the new member initialization syntax.

Fast forward to 2018 and C++17.
do not use std::string, use std::string_view literals
please do notice the 'constexpr' bellow. This is also an "compile time" mechanism.
no inline does not mean repetition
no cpp files are not necessary for this
static_assert 'works' at compile time only
using namespace std::literals;
namespace STANDARD {
constexpr
inline
auto
compiletime_static_string_view_constant() {
// make and return string view literal
// will stay the same for the whole application lifetime
// will exhibit standard and expected interface
// will be usable at both
// runtime and compile time
// by value semantics implemented for you
auto when_needed_ = "compile time"sv;
return when_needed_ ;
}
};
Above is a proper and legal standard C++ citizen. It can get readily involved in any and all std:: algorithms, containers, utilities and a such. For example:
// test the resilience
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
auto return_by_val = []() {
return STANDARD::compiletime_static_string_view_constant();
};
return return_by_val();
};
return return_by_val();
};
return return_by_val();
};
// actually a run time
_ASSERTE(return_by_val() == "compile time");
// compile time
static_assert(
STANDARD::compiletime_static_string_view_constant()
== "compile time"
);
Enjoy the standard C++

Related

Is it possilbe to initialize array in class with MSVS2017 C++ compiler without getting error C2864? [duplicate]

So I'm currently working on a school-project with C++, which I'm not really familiar with.
I would like to create a class, containing all my constants (string,int,double,own classes)
I was trying this, which has always worked for me in Java:
class Reference {
//Picture-Paths
public:
static const std::string deepSeaPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string shallowWaterPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string sandPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string rocksPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string snowPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
};
In C++, however, I get the following error:
Error C2864 'Reference::Reference::earthPath': a static data member with an in-class initializer must have non-volatile const integral type bio-sim-qt e:\development\c++\bio-sim-qt\bio-sim-qt\Reference.hpp 16 1
So is there any way for me to store for example String-Constants like this?
If yes, is there even a better way to do it? If no, is there another way (#define?) ?
In C++17, the recommended way of defining string constants if by using an inline constexpr std::string_view. Example:
namespace reference
{
inline constexpr std::string_view deepSeaPath{R"(something)"};
// ...
}
This is great because:
std::string_view is a lightweight non-owning wrapper that can efficiently refer to string literals without any additional costs.
std::string_view seamlessly interoperates with std::string.
Defining the variables as inline prevents ODR issues.
Defining the variables as constexpr makes it clear to both the compiler and other developers that these are constants known at compile-time.
If you do not have the luxury of using C++17, here's a C++11 solution: define your constants as constexpr const char* in a namespace:
namespace reference
{
constexpr const char* deepSeaPath{R"(something)"};
// ...
}
You should declare your data members in your header file, but the definitions should be placed in the source file, like this for example:
const std::string Reference ::earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
Read more in: Static Data Member Initialization.
PS: Classes do not use to expose into public scope their data members. Getter and Setter functions are used instead, while the data members are not in public scope. If all you need is your data members, then a namespace could be a better design choice, than a class.

Class containing Constants of std::string

So I'm currently working on a school-project with C++, which I'm not really familiar with.
I would like to create a class, containing all my constants (string,int,double,own classes)
I was trying this, which has always worked for me in Java:
class Reference {
//Picture-Paths
public:
static const std::string deepSeaPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string shallowWaterPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string sandPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string rocksPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
static const std::string snowPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
};
In C++, however, I get the following error:
Error C2864 'Reference::Reference::earthPath': a static data member with an in-class initializer must have non-volatile const integral type bio-sim-qt e:\development\c++\bio-sim-qt\bio-sim-qt\Reference.hpp 16 1
So is there any way for me to store for example String-Constants like this?
If yes, is there even a better way to do it? If no, is there another way (#define?) ?
In C++17, the recommended way of defining string constants if by using an inline constexpr std::string_view. Example:
namespace reference
{
inline constexpr std::string_view deepSeaPath{R"(something)"};
// ...
}
This is great because:
std::string_view is a lightweight non-owning wrapper that can efficiently refer to string literals without any additional costs.
std::string_view seamlessly interoperates with std::string.
Defining the variables as inline prevents ODR issues.
Defining the variables as constexpr makes it clear to both the compiler and other developers that these are constants known at compile-time.
If you do not have the luxury of using C++17, here's a C++11 solution: define your constants as constexpr const char* in a namespace:
namespace reference
{
constexpr const char* deepSeaPath{R"(something)"};
// ...
}
You should declare your data members in your header file, but the definitions should be placed in the source file, like this for example:
const std::string Reference ::earthPath = "E:\\Development\\C++\\Material\\terrain\\deep_sea.tga";
Read more in: Static Data Member Initialization.
PS: Classes do not use to expose into public scope their data members. Getter and Setter functions are used instead, while the data members are not in public scope. If all you need is your data members, then a namespace could be a better design choice, than a class.

How to ensure const static member initialization order?

I'm having a problem with initialization order of a const static string class member. Some code:
constants.h
class Constants
{
public:
// not used right now
Constants& getInstance();
const static std::string CONST_STRING;
};
constants.cpp
const std::string Constants::CONST_STRING = "my string";
Constants& Constants::getInstance();
{
static Constants c;
return c;
}
which is classic const static initialization (ignoring the getInstance). However, if I then try to use this constant elsewhere in another translation unit like this:
class OtherClass
{
public:
OtherClass()
{
// tried uncommenting next line
// Constants::getInstance();
std::string str( Constants::CONST_STRING );
std::cout << str;
}
}
OtherClass obj; // note global
the CONST_STRING is empty, i.e. it has been constructed but not initialized. I know that global initialization order is not defined across translation units and I'm guessing something like that applies here?
However, removing the commented out line that attempts to ensure that Constants is fully constructed before it is used (I don't believe it is needed but giving it a go....) still doesn't fix things.
Questions:
How can I ensure const static members are fully initialized before anyone tries to use them?
Is this the best C++11 way to have constants associated with a class? Is constexpr something that could be used here?
The initialization of globals within a translation unit is going to occur in hidden code within that translation unit. You can't control the order in which those bits of hidden code are going to be called.
Constants with basic data types can be initialized at compile time rather than run time, so this would work:
const char Constants::CONST_STRING[] = "my string";
Maybe this is what are you looking for:
const std::string & GetConstantsString(){
static const std::string CONST_STRING = "My string";
return CONST_STRING;
}
As #AndreyT pointed out, literal type const static only are allowed to have in-class initializers so my option #1 will not work

Defining const static that needs setting up at runtime

I'm making use of a class with a few utilities defined as static methods eg.
QDate SSIMUtils::ConvertSSIMDate(QString s) {
QDate rtnDt;
//...conversion code
return rtnDt;
}
I would like to define a few constants in this class eg. LOW_DATE and was thinking of putting in something like
const static QDate LOW_DATE; // Need to set this somewhere to 1/1/1970
Unfortunately, I can't define it pre-compile time like I would say an int eg.
const static int SSIMUtils::myI = 4;
because it requires the use of a setDate method.
My question is how should I define a static const that I need to set up codewise, as the constant requires initialisation. I'd been thinking of defining it in the .h file eg.
const static QDate LOW_DATE;
then in the .cpp file, at the top, doing something like
SSIMUtils::LOW_DATE.setDate(1970,1,1);
But this is syntactically incorrect. What I'd ultimately like to do is use this constant in other classes eg.
if (myQDate.compare(SSIMUtils::LOW_DATE)==0) {
// do something.
}
What's the right way to set up a constant value in a static class that you need to adjust at run time ie. like a constructor?
As I mentioned in a comment, QDate has a constructor equivalent to setDate(), which allows for initialisation of a 'const' object.
You must declare your static constant the following way:
myclass.h:
#include <QDate>
class myclass {
public:
const static QDate CONST_DATE;
};
myclass.cpp:
#include "myclass.h"
const QDate myclass::CONST_DATE(1970, 1, 1);
I tested this using a std::string instead of a QDate (no QT available right now), and it works just as you want.
It depends on where the necessary information for the
initialization comes, or rather, when it is available. If it's
always available, and the type supports copy, then you can
just write a function which returns the initialized type:
namespace {
MyType getInitialized()
{
MyType results;
// ...
return results;
}
}
static MyType const lowDate( getInitialized() );
If it doesn't support copy, you can derive from it, providing
a specialized constructor:
class MyTypeInitialized : public MyType
{
public:
MyTypeInitialized()
{
// ...
}
};
MyTypeInitialized lowDate;
This has the disadvantage of masking the true type from the
client code, but otherwise works well.
If the information isn't available until later; e.g. it depends
on command line arguments, then you may have to use a variant of
the singleton idiom, where you have two instance functions:
one of which takes the necessary arguments for initialization,
and must be called first. (Or that may even be overkill; it
might be sufficient to have a global std::unique_ptr<MyType
const> lowDate;, and initialize that with an object newed at
the start of main. The main different is in the client
syntax.)
You cannot change something declared constant at run-time, by definition.
The closest you can get to run-time constant initialization is to initialize in a class'
constructor initializer list:
SomeClass(int constantValue) :
myConstant(constantValue)
{
...
}
Given that you are building a static class, you are probably not constructing an object though. You can always resort to having a setter method which only allows setting the value once (in which case you can not declare the field const, obviously).
As the name implies, it is a constant, it cannot (should not) be changed once initialised. The only place that you can assign a value to a constant member variable is in the constructor (that is, without weird const_casts).
Your QDate may be trivial to construct -- using a static constant may not be better than creating a new date for that constant each time the function is called.
In the interest of answering the question, let's assume it is complex to construct and that a static constant is best idea. You can simply write:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
static const QDate LOW_DATE( /* ...construct it... */ );
QDate rtnDt;
//...conversion code
return rtnDt;
}
Note: Looks like SirDarius explained how you can construct this type directly, without an intermediate (+1), although a function-local static constant is generally much better than a global constant because global constants lead to some very tough initialization problems in C++.
This creates a function local static which will be initialized once, and in a thread safe manner before it is read and when the function is called.
If the instance cannot be constructed easily, it helps at times to initialize using the copy constructor and then creating an accessory function:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
struct F { static QDate Low() { return ...; } };
static const QDate LOW_DATE(F::Low()); // << initialize the constant using the copy ctor
QDate rtnDt;
//...conversion code
return rtnDt;
}
So the short approach using the construction provided by SirDarius using a function-local-static is:
QDate SSIMUtils::ConvertSSIMDate(QString s) {
static const QDate LOW_DATE(1970, 1, 1);
QDate rtnDt;
//...conversion code
return rtnDt;
}

define static string variable in c++ class

I have 2 questions:
Why is this possible for an int variable:
foo.h:
class foo{
private:
const static int a = 42;
};
but for a string variable I need to do it this way?
foo.h:
class foo{
private:
static string fooString;
};
foo.cpp:
string foo::fooString = "foo";
And also:
In my particular case foo::fooString should represent a path variable, and I would like that for every object of class foo there were just one instance of foo::string, representing a const value that should never change.
Is there another way to solve this problem?
Why is this possible for an int variable: [..] but for a string variable I need to do it this way?
Just because. Actually you can still make the string const but, yes, you have to define it outside of the class definition. You can only do in-place initialisation of static members when they are const and integral (or "of literal type").
(In C++11 you can even do it for non-static non-const members when they are of literal type.)
I would like that for every object of class foo there were just one instance of foo::string, representing a const value that should never change. Is there another way to solve this problem?
A static const std::string, as you might expect.
// C++03
struct T {
static const std::string foo;
};
const std::string T::foo = "lol";