static const member variable initialization - c++

Looks like I can init a POD static const member, but not other types:
struct C {
static const int a = 42; // OK
static const string b = "hi"; // compile error
};
Why?

The syntax initializer in the class definition is only allowed with integral and enum 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 to fulfil the one definition rule. If C++ allows the definition below;
struct C {
static const string b = "hi";
};
b would be defined in each translation unit that includes the header file.
C++ only allows to define const static data members of integral or enumeration type in the class declaration as a short-cut. The reason why const static data members of other types cannot be defined is that non-trivial initialization would be required (constructor needs to be called).

string is not a primitive type (like int) but is a class.
Disallowing this is sensible; the initialisation of statics happens before main. And constructors can invoke all sorts of functions that might not be available on initialisation.

I'll sum up the rules about direct class initialization on C++98 vs C++11:
The following code is illegal in C++03, but works just as you expect in C++11. In C++11, you can think of it as the initializers being injected into each of the constructors of POD, unless that constructor sets another value.
struct POD {
int integer = 42;
float floating_point = 4.5f;
std::string character_string = "Hello";
};
Making the fields mutable static members will break the code in both standards, this is because the static guarantees there to be only one copy of the variable and thus we have to declare the members in a exactly one file, just like we would do with global variables using the referred 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 make them, const static members a new array of rules arise:
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, from C++11 onwards, it is allowed to make static constants of non-integer trivial types variable. Strings unfortunately does not fit the bill, therefore we cannot initialize constexpr std::strings even in C++11.
All is not lost though, as an answer to this post mentions, you could create a string class functions as a string literal.
NB! Note that you this is metaprogramming at its best, if the object is declared as constexpr static inside a class, then, as soon as you enter run-time, the object is nowhere to be found. I haven't figured out 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 a conststr directly in you 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;
}

In C++17 :
If you can use static constexpr you will have the desired result, but if you cant : use the inline variable introduce by C++17.
In your case, since std::string does not have a constexpr constructor, the solution is inline static const std::string
Example :
#include <iostream>
int foo() { return 4;}
struct Demo
{
inline static const int i = foo();
inline static const std::string str = "info";
};
int main() {
std::cout << Demo::i << " " << Demo::str<< std::endl;
}
Live Demo

Related

Using inline static member instead of static member

I have a following struct:
#include <iostream>
struct Foo
{
static int a; // declaration
inline static int b = 10; // declaration and definition
};
int Foo::a = 10; // definition
int main()
{
std::cout << Foo::a << "\n"; // --> 10
std::cout << Foo::b << "\n"; // --> 10 (same result as Foo::b)
return 0;
}
It is "easier" to use inline static to achieve same goal as when static is used.
Is there any case when using static members for class instead of inline static members is more preferable/required?
Note : there is an obvious case when one uses C++14 or lower standard.
You'd see it if you ever try to create "stateful enums". Basically, classes that capture a little data and there is a handful of "named constants" of that type that you'd want to codify as static data members. To illustrate:
struct RGB {
inline static RGB c1{1};
inline static RGB c2{2};
RGB(int, int = 0, int = 0);
};
This will be ill-formed, whereas this will not:
struct RGB {
static RGB c1;
static RGB c2;
RGB(int, int = 0, int = 0);
};
RGB RGB::c1{1};
RGB RGB::c2{2};
Live example
The reason is that a static data member may have an incomplete type, but it must be complete when initialised.
It will naturally pop up when playing with constexpr static members. Come C++17, they are implicitly inline, so you'd have to break the declaration from definition if you want to have them:
struct RGB {
static const RGB c1;
static const RGB c2;
constexpr RGB(int, int = 0, int = 0){}
};
constexpr RGB RGB::c1{1};
constexpr RGB RGB::c2{2};
Live example
Those are valid constant, and are usable in constant expressions. But they cannot be defined inline as static data members. They are still technically inline data members on account of being constexpr, but are not defined inline (mind though that it's true prior to C++17 too, but the constant cannot be defined in a header for redefinition errors, so they are essentially unusable).

Constructor for `const` object

Consider this code:
#include <iostream>
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 ); // Normal case, nothing new.
const test t2( txt2 ); // Since object is const, I'd like to be able to pass a const argument in.
}
It blows up with the error:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
const test t2( txt2 );
Then I tried to add a second constructor to test whether the compiler could select the right one for t2, my const object:
test( const char *arg )
: _arg( arg )
{}
but then the error is:
error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
: _arg( arg )
So declaring my object as const does not make its fields const as well.
How to properly declare my class constructors so that it can handle const and non-const object creation?
How to properly declare my class constructors so that it can handle const and non-const object creation?
The object isn't const during construction, or the constructor wouldn't be able to initialize the object (since all data members would be const).
So, constructors can't be const-qualified and you can't have a constructor overload used for const objects.
Now, you can overload on the argument, but your data member always has type char * during construction, although it's qualified to char * const (not const char *) when used in a const-qualified instance of test.
Options are:
overload constructor on argument type, and store a char * always. If you're passed a const char * you have to copy it (and you're responsible for knowing that you own and must deallocate this memory)
In this scheme, you rely on keeping the pointer private and using const-qualified accessors to stop the contents of the pointer being changed via a const-qualified object.
Again, you need to do this manually because char * const is a different type than const char *, because constness of the pointed-to type isn't related to constness of the pointer: having a const instance of your class just stops you mutating the pointer, not the characters it points to.
overload constructor and store a const char * always. This avoids copying but obviously doesn't work if you sometimes need to change the pointed-to characters
just write different mutable-string and immutable-string classes
If it helps, consider this:
template <typename T> struct test {
T* p_;
test(T *p) : p_(p) {}
};
template <typename T> test<T> mktest(T *p) { return {p}; }
and note that
const char *ccp = "immutable characters in a string literal";
char *cp = strdup(ccp);
auto a = mktest(ccp);
auto b = mktest(cp);
gives a the type test<const char>, and b the type test<char> and that these types are not the same, are not convertible, and are no more closely related in the language than to test<T> for any other type T.
A note: this is a long answer for a use case that might be a bad design. Yet, the reason and the main focus for the long answer is:
to show and explain what is not possible
to present a way in which one can make the compiler decide based on the constness of a parameter whether to create a holding const object and to preserve this information even if the object is passed on. Which is very close to the OP request.
As explained in other answers, you can have two constructors, one for const parameter and the other for non-const, but both constructors would just create an object that can be either const or non-const. So this doesn't help.
Another approach could be to have a factory method that would create either a const object or a non-const, according to the constness of the parameter. Though this may sound promising it would not allow to preserve the semantics of the difference between the two, as shown in the following pseudo code:
// creating an object holding a const, using the factory method `create`:
const MyClass const_holder = create(const_param);
// however you cannot prevent this:
MyClass non_const_holder = create(const_param);
The factory would create in the second case above a const object that would be copied or moved (or just created directly as non_const_obj with copy elision, since C++17 as mandatory copy elision). You cannot do anything to avoid the second case unless you delete copy and move, in which case the first case wouldn't work also and the all thing collapses.
So, without creating actually two different types it is impossible to preserve the information of which constructor was used and to avoid assignment of an object created with const param into an object that doesn't.
However, there is no real need to bother the user with the fact that there are two classes, with a proper template implementation the user can have simple code that gives the feeling that there is only one class in the game, something like:
// creating a const holder with a factory method
// the type would *remember* that it is holding a const resource
// and can act accordingly
auto const_holder = create(const_param);
// and you can also create a non const holder with the same factory
auto non_const_holder = create(param);
These operations would be allowed:
// (a) calling a non const method on the content of the non const holder
non_const_holder->non_const_method();
// (b) assigning a non const holder into a const holder object
// -- same as assigning char* to const char*
const_holder = non_const_holder;
These operations would NOT be allowed:
// (a) calling a non const method on the content of a const holder
const_holder->non_const_method(); // should be compilation error
// (b) assigning a const holder into a non const holder object
// -- same as one cannot assign const char* to char*
non_const_holder = const_holder; // should be compilation error
In a way, this is very similar to the idea of propagate_const...
The code would have a factory method:
template<class T>
Pointer<T> create(T* t) {
return Pointer<T>::create(t);
}
And two implementations for the template class Pointer.
base template:
template<class T>
class Pointer {
T* ptr;
Pointer(T* p) : ptr(p) {}
friend class Pointer<const T>;
public:
// factory method
static Pointer create(T* p) {
return p;
}
operator T*() { return ptr; }
operator const T*() const { return ptr; }
};
and a specialized one for the const version:
template<class T>
class Pointer<const T> {
const T* ptr;
Pointer(const T* p) : ptr(p) {}
public:
Pointer(const Pointer<T>& other) {
ptr = other.ptr;
}
// factory method
static const Pointer create(const T* p) {
return p;
}
operator const T*() { return ptr; }
operator const T*() const { return ptr; }
};
The main would look like:
int main() {
char str[] = "hello";
const char* const_str = "hello";
// non-const - good!
auto s1 = create(str);
// const holding non-const - ok!
const auto s2 = create(str);
// non-const that holds const - good!
auto s3 = create(const_str);
// also possible: const holding const
const auto s4 = create(const_str);
s1[4] = '!'; // OK
// s2[0] = '#'; // obviously doesn't compile - s2 is const
// s3[0] = '#'; // doesn't compile - which is good - s3 holds const!
// s4[0] = 'E'; // obviously doesn't compile - s4 is const
// avoids assignment of s3 that holds a const into s1 that holds a non-const
// s1 = s3; // <= doesn't compile - good!
s3 = s1; // allows assignment of `holding-non-const` into `holding-const`
s3 = s2; // allows assignment of `holding-non-const` into `holding-const`
s3 = s4; // allows assignment of `holding-const` into `holding-const`
}
Code: http://coliru.stacked-crooked.com/a/4729be904215e4b2
The problem you experience goes a bit deeper. It's an indication of a design issue.
You would like to expose only part of the API. You say that for a const object you will call only const methods and for non-const you can do anything. But this is problematic.
Either you accept const object strip it from const qualifier, and won't call non-const methods by a silent contract. Or, you need to limit methods, which makes a different object - type-wise.
C# library does it by providing a limited interface which wraps around original object and exposes only const methods. Something like this:
#include <iostream>
using namespace std;
struct A {
void f1() const {cout << "foo\n"; }
void f2() {cout << "bar\n"; }
};
struct readonlyA {
readonlyA(const A& a) : _a(a) {};
void f1() const {_a.f1();};
private:
const A& _a;
};
int main() {
A a;
readonlyA roA(a);
a.f2();
roA.f1();
roA.f2(); // error
return 0;
}
It's basically a read-only proxy.
The compiler does not care about what you actually do with the object at runtime.
Const works because the compiler will forbid certain things at compile time that could potentially change the object. This might be over-restrictive in certain situations, as the compiler often does not have the full picture of what's going on in the program.
Take for example the invocation a non-const member function on a const object: Even if the member function does not actually change the object's state, the compiler will still forbid it because the non-const function could potentially change the object.
Similar in your example: Even though you don't change the member for that particular const instance of the class, there could be other non-const instances of the same class somewhere, which is why it will refuse construct any instance of the class from a const object.
If you want a class that is guaranteed to leave its members unchanged, that would be a different type:
class test
{
public:
test( char *arg )
: _arg( arg )
{}
char *_arg;
};
class immutable_test
{
public:
immutable_test(char const* arg)
:_arg(arg)
{}
char const* _arg;
};
int main( )
{
char *txt1 = "Text one"; // Ignore this warning.
const char *txt2 = "Text two";
test t1( txt1 );
immutable_test t2( txt2 );
}
It can't be done. Just because the object is const, it doesn't mean that it guarantees the char* won't be used to modify its value. The constructor can mutate the argument, and code outside the class can modify its content if it is exposed. Consider the following example.
struct Test {
char* buffer;
Test(char* buffer):
buffer(buffer)
{
buffer[0] = 'a';
}
char* get() const {
return buffer;
}
};
int main(int argc, char* argv[]) {
std::string s{ "sample text" };
const Test t(s.data());
t.get()[1] = 'b';
t.buffer[2] = 'c';
std::cout << s << '\n';
}
The above prints abcple text, even though t is const. Even though it never modifies its members, it does change the pointed-to string and it allows outside code to modify it, too. This is why const objects cannot accept const char* arguments to initialize their char* members.
The compiler is preventing you from carelessly discarding the constness...
class test
{
public:
test(const char *arg)
: _arg(arg)
{}
const char *_arg;
};
Interesting.
Look at the example below (object myclass2) to learn how a const object does not necessarily provide the protection that you need!
#include <iostream>
#include <cctype>
#include <cassert>
class MyClass
{
public:
MyClass(char * str1, size_t size1) : str{str1}, size{size1}
{
}
char * capitalizeFirstChar()
{
*str = std::toupper(*str);
return str;
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
char * str;
size_t size;
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// UGLY!!! const_cast
const MyClass myclass2(const_cast<char *>(str2), sizeof(str2) / sizeof(*str2));
// myclass2.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
myclass2.str[0] = 'Z'; // WILL COMPILE (!!) and should cause a segfault
// The const myclass2, CANNOT PROTECT THE OBJECT POINTED TO by str
// Reason: the member in MyClass is
// char *str
// not
// const char *str
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Ok, the str member issue is actually best solved, by just making the members private.
But what about that ugly const_cast?
One way of solving this is splitting into a Const baseclass, and deriving for non-const behaviour (working with const-casts). Like this perhaps:
#include <iostream>
#include <cctype>
#include <cassert>
class MyClassConst
{
public:
MyClassConst(const char * str1, size_t size1) : str{str1}, size{size1}
{
}
char nthChar(size_t n) const
{
assert(n < size);
return str[n];
}
const char * str;
size_t size;
};
class MyClass : public MyClassConst
{
public:
MyClass(char * str1, size_t size1) : MyClassConst{const_cast<const char *>(str1), size1}
{
}
char * capitalizeFirstChar()
{
char * cp = const_cast<char *>(str);
*cp = std::toupper(*cp);
return cp;
}
};
int main()
{
{
static char str1[] = "abc";
MyClass myclass1(str1, sizeof(str1) / sizeof(*str1));
myclass1.capitalizeFirstChar();
std::cout << myclass1.nthChar(0) << std::endl;
}
std::cout << "----------------------" << std::endl;
{
static const char str2[] = "abc";
// NICE: no more const_cast
const MyClassConst myclass2(str2, sizeof(str2) / sizeof(*str2));
// a.capitalizeFirstChar(); // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
char c = 'x';
// myclass2.str = &c; // commented: will not compile
// The const myclass2, does not
// allow modification of it's members
// myclass2.str[0] = 'Z'; // commented: will not compile
std::cout << myclass2.nthChar(0) << std::endl;
}
}
Is it worth it? Depends.
One is kindof trading the const-cast outside of the class... for const-cast inside the class. So maby for library code (including ugly internals, and static code analysis exceptions), with clean outside usage, it's a match...

Different behavior observed with constexpr auto/char-array variable

Following up with this question Having a constexpr static string gives a linker error
In the question, this code wasn't able to compile:
#include <iostream>
struct Test { static constexpr char text[] = "Text"; };
int main()
{
std::cout << Test::text << std::endl; // error: undefined reference to `Test::text'
}
From the comment, this code is able to compile:
#include <iostream>
struct Test { static constexpr auto text = "Text"; };
int main()
{
std::cout << Test::text << std::endl;
}
My question is why the auto version works but the array of char version doesn't?
Could you please point out the statement in the standard allowing the second version and disallowing the first?
I took a look at Strange behavior with constexpr static member variable but it seems to be another question.
A declaration of a static data member in class is never a definition.
The difference between your examples is that only one requires a definition of text.
The auto version deduces char const*, hence text is only subject to an lvalue-to-rvalue conversion and not odr-used. By contrast, the first code effectively passes text's address, odr-use-ing it - i.e. necessitating a definition.
struct Test { static constexpr auto text = "Text"; };
resolves to
struct Test { static constexpr const char * text = "Text"; };
So the second expression is a constexpr value of a pointer not an array.

static const member of a struct is not defined

Using an 03 standard-compliant compiler (safety-critical variant of gcc-3.3.2).
The standard says that static member objects must be defined (9.4.2 (4)). It also states that the one-definition rule holds, but no diagnostic is required (9.4.2 (5)). Is the following code valid?
struct fred
{
static const int JOE=1;
int m_joe;
fred() : m_joe(JOE) {}
};
That is, there is no "static const int fred::JOE;".
I ask because we have a case (apparently) where a static const int in a template class was never defined, and the code worked in some contexts, but not others. I replaced the static const int with an enum, and it worked in all cases.
Were we definitely in the Land of Undefined Behavior?
A static const int defines a compile-time constant; I'm afraid I can't refer to a specific part of the standard. The only time you need a definition for it is if you try to take the address of it or create a reference. If you use an enum instead, the compiler will create a temporary variable for you when you need a reference.
struct test
{
static const int one = 1;
enum { two = 2 };
};
void printint(const int & i)
{
cout << i << endl;
}
int main() {
printint(test::one); // error
printint(test::two); // no error
return 0;
}

Is there a way to make a C++ struct value-initialize all POD member variables?

Suppose I have a C++ struct that has both POD and non-POD member variables:
struct Struct {
std::string String;
int Int;
};
and in order for my program to produce reproduceable behavior I want to have all member variables initialized at construction. I can use an initializer list for that:
Struct::Struct() : Int() {}
the problem is as soon as I need to change my struct and add a new POD member variable(say bool Bool) I risk forgetting to add it to the initializer list. Then the new member variable will not be value-initialized during struct construction.
Also I can't use the memset() trick:
Struct::Struct()
{
memset( this, 0, sizeof( *this ) ); //can break non-POD member variables
}
because calling memset() to overwrite already constructed non-POD member variables can break those.
Is there a way to enforce value-initialization of all POD member variables without explicitly adding their initialization in this case?
The cleanest way would be to write the auto-initialzed template class initialized<T>:
EDIT: I realize now it can be made even more flexible by allowing you to declare initialized<Struct>. This means that you can declare initialization without modifying the original Struct. The default initialization 'T()' was inspired on Prasoons answer.
template<class T>
struct initialized
{
public:
initialized()
{ value = T(); }
initialized(T t)
{ value = t; }
initialized(const initialized<T>& x)
{ value = x.value; }
T* operator &() { return &value; }
operator T&() { return value; }
private:
T value;
};
struct PodStruct
{
std::string String;
int Int;
};
struct GlorifiedPodStruct
{
std::string String;
initialized<int> Int;
};
void Test()
{
GlorifiedPodStruct s;
s.Int = 1;
int b = s.Int;
int * pointer = &s.Int;
initialized<PodStruct> s2;
}
This compiles, but may need more conversion operators, handling of keywords like volatile, etc. But you get the idea.
Linked Question here
Is there a way to enforce value-initialization of all POD member variables without explicitly adding their initialization in this case?
I am not sure whether something like that is possible [directly] or not but the following works
prasoon#prasoon-desktop ~ $ cat check.cpp && clang++ check.cpp && ./a.out
#include <iostream>
struct Struct {
std::string String;
int Int;
bool k;
// add add add
};
struct InStruct:Struct
{
InStruct():Struct(){}
};
int main()
{
InStruct i;
std::cout<< i.k << " " << i.Int << std::endl;
}
0 0
prasoon#prasoon-desktop ~ $
You can add a base struct:
struct PODStruct
{
PODStruct(unsinged int count) { memset( this, 0, count);}
};
And then your struct derived from this base struct, first place if you have more than one base structs,
struct Struct : PODStruct
{
Struct();
std::string Str;
int Int;
}
Struc::Struct() : PODStruct(sizeof(Struct))
{
}