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).
Related
I am using g++4.8.0, which doesn't contain earlier constexpr bug. Thus below code works fine:
constexpr int size() { return 5; }
int array[size()];
int main () {}
However, if I enclose both the variable inside a class as static, then it gives compiler error:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
int main () {}
Here is the error:
error: size of array ‘array’ is not an integral constant-expression
Is it forbidden to use constexpr in such a way or yet another g++ bug?
Yes, it is ill-formed. Here's why:
A constexpr function needs to be defined (not just declared) before being used in a constant expression.
So for example:
constexpr int f(); // declare f
constexpr int x = f(); // use f - ILLEGAL, f not defined
constexpr int f() { return 5; } // define f, too late
function definitions inside a class specifier (as well as initializers and default parameters) are essentially parsed in an order like they were defined outside the class.
So this:
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
Is parsed in this order:
struct X {
constexpr inline static int size(); // function body defered
static const int array[size()]; // <--- POINT A
};
constexpr inline int X::size() { return 5; }
That is, parsing of function bodies are defered until after the class specifier.
The purpose of this deferral of function body parsing is so that function bodies can forward reference class members not yet declared at that point, and also so they can use their own class as a complete type:
struct X
{
void f() { T t; /* OK */ }
typedef int T;
};
Compared to at namespace scope:
void f() { T t; /* error, T not declared */ }
typedef int T;
At POINT A, the compiler doesn't have the definition of size() yet, so it can't call it. For compile-time performance constexpr functions need to be defined ahead of their use in the translation unit before being called during compile, otherwise the compiler would have to make a multiple passes just to "link" constant expressions for evaluation.
Apparently it's not even a bug, because its status is RESOLVED INVALID, which means that the people behind GCC and that bugzilla, after reviewing the problem, don't think that this is a GCC bug.
I remind you on that page because there is also an answer for this behaviour in one of the related posts.
I just wanted to add that even though this may not be good practice and will restrict you to defining the class body in the same compilation unit that its declared, it's possible to force the compiler to compile the definition of the function bodies at the same point as its declaration by adding a redundant template parameter:
template <typename = void>
struct X {
constexpr static int size() { return 5; }
static const int array[size()];
};
int main()
{
X<> x{};
...
}
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;
}
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
Background
What I'm trying to achieve: I'm trying to implement something like a Java enum (ie. enum that has some additional functionality). I came up with a solution using two classes, where one class represents a value and the other acts as an enumeration of possible values using static variables to represent each value. I want it to be a real replacement of enum, including the possibility to use the enum values in template instantiation. For this to work, an enum value needs to be a constant expression (constexpr). However, I'm not sure if I use the constexpr correctly.
The Code
Here is the code that I came up with:
class EnumType {
public:
enum Enum {val_A, val_B, val_C};
friend class EnumTypeList;
EnumType()
: m_ID(val_A), m_foo(0) {}
constexpr operator Enum() const {return m_ID;};
constexpr unsigned int getFoo() const {return m_foo;};
protected:
constexpr EnumType(const Enum v, const int foo)
: m_ID(v), m_foo(foo) {}
private:
Enum m_ID;
int m_foo;
};
class EnumTypeList {
public:
static constexpr EnumType A = EnumType(EnumType::val_A, 5);
static constexpr EnumType B = EnumType(EnumType::val_B, 4);
static constexpr EnumType C = EnumType(EnumType::val_C, 8);
};
The class EnumType holds the information of each value and provides some additional functions (here it is storing the additional value m_foo that can be accessed using getFoo() function). The enumeration itself is represented by the EnumTypeList that contains static constexpr variables, where each variable represents a possible value of an enum. This code allows me to use the variables from EnumTypeList in place of EnumType::Enum. Even in templates like in the following code:
template <EnumType::Enum T>
class Test {
public:
void test() {
std::cout << "Enum is not A" << std::endl;
}
};
template <>
class Test<EnumType::val_A> {
public:
void test() {
std::cout << "Enum is A" << std::endl;
}
};
int main() {
Test<EnumTypeList::A> a;
a.test();
Test<EnumTypeList::B> b;
b.test();
// this shouldn't compile
/*EnumType x = EnumTypeList::C;
Test<x> c;
c.test();*/
}
This works as I would expect – I can use the values from EnumTypeList in place of EnumType::Enum in template instantiation as demonstrated above, but I can't do it with EnumType x = EnumTypeList::C;
The Problem
While the code compiles correctly without any warning under gcc and clang, I'm not sure if I use the constexpr correctly. The thing is that while the EnumType constructor and the conversion operator operator Enum() are constexpr, they both access variables m_ID and m_foo that are not constant (because I need assignment operator).
This is fine, members of literal types are allowed to be modifiable.
In order to use the type in a constant expression you must construct it with constant arguments, but that's OK because you do that;
static constexpr EnumType A = EnumType(EnumType::val_A, 5);
The object constructed is a valid constant expression so can be used to initialize the constexpr variable A. You don't modify the members of the object, so it doesn't matter that they are modifiable.
Clang in particular is very strict about constant expressions, if you were doing something wrong it would give an error.
This object can be used where a constant expression is needed:
constexpr EnumType A5(EnumType::val_A, 5);
e.g.
constexpr int i = A5.getFoo();
This object cannot:
EnumType A6(EnumType::val_A, 6);
constexpr int i = A6.getFoo(); // error
Consider the following simplified template meta-programming code that implements an Angle class that is internally storing the modulo 360 degrees reduced value.
#include <iostream>
#include <typeinfo>
template<int N, int D>
struct Modulus
{
static auto const value = N % D;
};
template<int N>
struct Angle
{
static auto const value = Modulus<N, 360>::value; // ERROR
//static int const value = Modulus<N, 360>::value; // OK
//static auto const value = N % 360; // OK
typedef Angle<value> type;
};
int main()
{
std::cout << typeid(Angle<30>::type).name() << "\n";
std::cout << typeid(Angle<390>::type).name() << "\n";
return 0;
}
Output on Ideone
With Visual C++ 2010 Express, I can do static auto const = Modulus<N, 360>::value, but with MinGW gcc 4.7.2 (Nuwen distro) or Ideone (gcc 4.5.1) I have to either explicitly denote the type as static int const value = Modulus<N, 360>::value or I have to use auto with the full modular expression as static auto const value = N % 360;.
Question: Which compiler is correct acccording to the new C++11 Standard?
The code is valid. Visual C++ is right to accept it and gcc is wrong to reject it (for completeness, Clang 3.1 also accepts the code). The specification states that (C++11 7.1.6.4[dcl.spec.auto]/4):
The auto type-specifier can also be used...in declaring a static data member with a brace-or-equal-initializer that appears within the member-specification of a class definition.
Your value is a static data member. It has a brace-or-equal-initializer (that is the = Modulus<N, 360>::value part of the declaration), and the initializer appears within the member-specification of the class definition (i.e., it's what mortals might call an "inline initializer").