constexpr in class without static - c++

I have a situation where I need to store a compile time constant in a header, and I do it in the class I'm using it in as I don't want to expose the constant to other files that include this header. (as well as the fact that it depends on another hidden struct)
Like this:
namespace ns {
class bla {
private:
struct internalStruct {
// ...
};
// I put it in the class as I don't want other files to be able to see this
constexpr const size_t compileConstant = sizeof(internalStruct) * 8;
};
}
The problem is I get a
Constexpr is not valid here
error. The solution is to add static, however I read that constexpr integral members should be inline.
What should I do?

Adding static should be perfectly fine for your use case. That's what the reference states too:
A constexpr specifier used in a function or static data member (since
C++17) declaration implies inline.
And since this is a compile-time constant, you might as well have it shared across all class instances rather than on a per-instance basis (which is usually how even const variables are used).

Related

Linking Static Variable in Abstract Class [duplicate]

Say that I have a class that requires a few constants to function. Several member functions require use of these constants. Use of #define is frowned upon since it can cause collisions. The constants are hex patterns of 8 or 16 bits and are stored as uint8_t or uint16_t. These constants also don't change from instance to instance of the class, and therefore memory (albeit very little memory) can be saved by having only one copy of the constants.
Is there anything improper, or perhaps of better way of accomplishing the above instead of simply doing something like the following:
// mycode.h
// .......
class myclass {
private:
static const uint16_t kMyClassConstant_ = 0xBEEF;
// .......
};
Thanks in advance for the help.
Given your description of the situation, I'd say using static const members is a good approach. In C++11 you may want to change it into static constexpr to emphasize it's a compile-time constant, although nothing will effectively change as a result of that.
If you refer to myclass::kMyClassContant_ somewhere in the code in a way that is relevant under the one-definition-rule (odr), esp. in contexts that require a reference (including const-reference), the compiler will complain that there is no definition of the constant. Merely declaring and initializing it inside the class isn't sufficient in this case. This may force you to separate declaration and definition:
// mycode.h
class myclass {
private:
static const uint16_t kMyClassConstant_;
};
// mycode.cpp
const uint16_t myclass::kMyClassConstant_ = 0xBEEF;
To avoid the trouble of maintaining separate declarations and definitions, some people prefer declaring an inline constexpr function instead of an actual variable:
// mycode.h
class myclass {
private:
static constexpr uint16_t kMyClassConstant_()
{ return 0xBEEF; }
};
This is a correct work-around for many of the odr-related problems, and it does not cause any loss in performance. Whether it is really useful depends on how much of a burden it is to maintain separate declarations and definitions of an ordinary static constant. If you expect your constants to never change as your code evolves, using ordinary static constants with separate definitions is preferable. But if you modify the definitions of the constants frequently, having to re-compile the definition file and re-link it to all relevant parts of the project may make you consider the function-based solution above as a better alternative.
A final comment on the data type: Forcing it into 16 bits using std::uint16_t can be useful if you need to store lots of these values in compact form. Otherwise, the actual size may not really matter, in which case std::uint_fast16_t (which may be larger than 16 bits) may be better.
You could use type traits to implement this:
#include <type_traits>
class myclass {
private:
typedef std::integral_constant<uint16_t , 0xBEEF> kMyClassConstant;
// ...
};
used as myclass::kMyClassConstant::value.
This shows the purpose of implementing an integral constant and prevents you from accidentaly taking an address of the constant.
Since C++17, we have access to inline variables, which take care of the odr-related problems. Several options:
// mycode.h
class myclass {
static const inline uint16_t kMyClassConstant_ = 0xBEEF;
};
Or, if it can be marked constexpr (like in this case):
// mycode.h
class myclass {
static constexpr inline uint16_t kMyClassConstant_ = 0xBEEF;
};
Which can be simplified to:
// mycode.h
class myclass {
static constexpr uint16_t kMyClassConstant_ = 0xBEEF;
};
Because in C++17 constexpr implies inline for static data members.

Where to define compile-time constants?

I made a super simple design to start solving a problem.
Now, this might seem like super trivial at first, but since there are tons of ways to do this, it confuses me, due to my lack of professional experience.
Where would I define those compile time constants? (Always suppose I'm using the highest current C++ standard version)
In a namespace? Inside the class? In a .h outside the class? In the .cpp outside the class? Just use them as magic numbers and add some comment? static? non-static? const? constexpr? template the deck size in case its bigger?
What I thought of:
class JolloManager
{
private:
constexpr static int rounds = 3;
constexpr static int deckSize = 52;
constexpr static int princeId = 1;
constexpr static int princessId = 2;
std::array<int, deckSize> deck;
public:
JolloManager() {};
};
Is this correct?
In C++17, defining compile-time integer constants is easy.
First, you should decide whether or not the constant should be scoped to a class. If it makes sense to have it as a class member (e.g., it pertains to the concept that the class represents) then make it a class member. Otherwise, don't.
As a class member, write:
class JolloManager {
constexpr static int rounds = 3;
};
That's it. No out-of-line definition is required anymore in C++17.
If it's not going to be a class member, but you want everyone who includes your header to be able to access the value, then write this in the header:
inline constexpr int rounds = 3;
(Technically, the reason to use inline is to avoid ODR violations when the variable is ODR-used by an inline function in multiple translation units.)
If the value is an implementation detail that only one .cpp file needs access to, then write the following in that .cpp file to give it internal linkage (i.e., prevent clashing with names in other translation units):
constexpr int rounds = 3; // no `inline` this time
Finally, if the constant is only needed by a single function, you can make it local to that function:
void foo() {
constexpr int rounds = 3;
}

Why local classes can't have static data members? [duplicate]

What is the reasoning to why static const members cannot exist in local classes? It seems like a rather silly restriction.
Example:
void foo() {
struct bar {
int baz() { return 0; } // allowed
static const int qux = 0; // not allowed?!?
};
}
struct non_local_bar {
int baz() { return 0; } // allowed
static const int qux = 0; // allowed
};
Quote from standard (9.8.4):
A local class shall not have static data members.
From the standard section 9.4.2:
If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constant-initializer which shall be an integral constant expression.
In that case, the member can appear in integral constant expressions
within its scope. The member shall still be defined in a namespace
scope if it is used in the program and the namespace scope definition
shall not contain an initializer.
Basically, local classes have no linkage, and static data members require a linkage.
Since there's no way to define a static data member of a local class in namespace scope (a declaration with an initializer is not a definition), they are not allowed, whether they are of const integral type or not. On the surface it may seem like the compiler should just be able to inline the value, but then what happens if you try to access a pointer to the member? With namespace scoped classes you'd just get a linker error, but local classes have no linkage.
I guess in theory they could just allow you to use static const integral types in local classes as long as they are only used in integral constant expressions, but it would probably just put too much of a burden on the standards body and compiler vendors to differentiate for very little practical value; local static variables are accessible from local classes, so using a local static const should be just as good.
I dont think there is a.reason. Normal static datamembers are disallowed because there is no way to define them after being declared.
Also dont forget you can create a local const variable outside the.class that you can use inside the class as long as you only read its value (that is, as long as you dont take.its.address).
Static members of a class need to be defined in global scope, e.g.
abc.h
class myClass {
static int number;
};
abc.cpp
int myClass::number = 314;
Now, since the scope inside void abc(int x) is not global, there is no scope to define the static member.
As things progress, we now have C++11 and with that you can define integral constants variable members in your classes.
class test
{
public:
const int FOO = 123;
[...snip...]
};
That works when you compile with C++11. Notice that the static keyword is not used. When compiling with optimizations turned on, those variables will likely all get optimized out. In debug, though, they appear in your structure as regular variable members.
Note, however, that the size of the class/structure will still include that variable. So here it is likely 4 bytes for the variable FOO.
However, in most cases, classes defined in a function will completely be optimized out so this is a great way of doing things (a good 50% of my classes have such variable members!)

Why aren't static data members allowed in local classes?

What is the reasoning to why static const members cannot exist in local classes? It seems like a rather silly restriction.
Example:
void foo() {
struct bar {
int baz() { return 0; } // allowed
static const int qux = 0; // not allowed?!?
};
}
struct non_local_bar {
int baz() { return 0; } // allowed
static const int qux = 0; // allowed
};
Quote from standard (9.8.4):
A local class shall not have static data members.
From the standard section 9.4.2:
If a static data member is of const integral or const enumeration
type, its declaration in the class definition can specify a
constant-initializer which shall be an integral constant expression.
In that case, the member can appear in integral constant expressions
within its scope. The member shall still be defined in a namespace
scope if it is used in the program and the namespace scope definition
shall not contain an initializer.
Basically, local classes have no linkage, and static data members require a linkage.
Since there's no way to define a static data member of a local class in namespace scope (a declaration with an initializer is not a definition), they are not allowed, whether they are of const integral type or not. On the surface it may seem like the compiler should just be able to inline the value, but then what happens if you try to access a pointer to the member? With namespace scoped classes you'd just get a linker error, but local classes have no linkage.
I guess in theory they could just allow you to use static const integral types in local classes as long as they are only used in integral constant expressions, but it would probably just put too much of a burden on the standards body and compiler vendors to differentiate for very little practical value; local static variables are accessible from local classes, so using a local static const should be just as good.
I dont think there is a.reason. Normal static datamembers are disallowed because there is no way to define them after being declared.
Also dont forget you can create a local const variable outside the.class that you can use inside the class as long as you only read its value (that is, as long as you dont take.its.address).
Static members of a class need to be defined in global scope, e.g.
abc.h
class myClass {
static int number;
};
abc.cpp
int myClass::number = 314;
Now, since the scope inside void abc(int x) is not global, there is no scope to define the static member.
As things progress, we now have C++11 and with that you can define integral constants variable members in your classes.
class test
{
public:
const int FOO = 123;
[...snip...]
};
That works when you compile with C++11. Notice that the static keyword is not used. When compiling with optimizations turned on, those variables will likely all get optimized out. In debug, though, they appear in your structure as regular variable members.
Note, however, that the size of the class/structure will still include that variable. So here it is likely 4 bytes for the variable FOO.
However, in most cases, classes defined in a function will completely be optimized out so this is a great way of doing things (a good 50% of my classes have such variable members!)

Why can't we have non-const class-level static variables?

Why does the Visual C++ compiler refuse to compile this code?
I obviously know that the error is:
Error C2864: Singleton<T>::p:
Only static const integral data members can be initialized within a class
but why? (i.e. is there a technical reason why it is not allowed?)
Is this compiler-specific behavior or is it mandated by the standard?
It seems to be fine at the global scope, so why not at the class scope?
It also seems like not all compilers mind this.
Also, what is the proper way of fixing this?
template<typename T>
struct Singleton
{
static T *p = 0; // Error C2864
static T *getInstance() { /*...*/ return p; }
};
That's standard behavior. Only static const integral members can be initialized without a proper definition. All other types need to be defined somewhere, and the initialization is written at the point of definition:
template<typename T>
struct Singleton {
static T *p;
static T *getInstance() { /*...*/ return p; }
};
template<typename T>
T *Singleton<T>::p = 0;
Objects must be defined somewhere. If you define them within your class then its defined at a header file, and you get a different object for each compilation unit that includes it. This is relaxed for const integral types and if you don't define them then the compiler just replaces it with its literal value. Taking the address of such static const integral would still result in a linker error if no definition is provided.
You can have this type of variable, but you cannot initialize it inside the class definition. The only type of variable that may be initialized the way you are asking is a static const.
A fixed version of your class definition removes the = 0, and adds this below the class definition:
template<typename T>
T *Singleton<T>::p = 0;
This is standard behavior. I'm not sure there is a technical reason, my guess would be it is for consistency with instance members (which cannot be initialized this way, either). Instance variables, of course, have constructor initializer lists instead.
As everyone pointed out, you cannot define a non-const, non-integral type in the body of a class (at least not with C++03, it changed with C++11 but I'm not sure how exactly). However, you can do it differently and clean.
template<typename T>
struct Singleton {
static T* getInstance() {
static T* p = NULL;
/*...*/
return p;
}
};
Declarations are meant to go into header files, where they will be compiled many times - each place they are included.
Static variables should only have one definition, so that only one copy will exist in the entire program. This means it needs to be in a source (.cpp) file. Assigning the value needs to be put at that spot.
Static constant integers are an exception to the above rules, because they can become compile time constants. When they're used, a literal value is substituted for the class member.
You cannot assign a non-static in the class body like that. Instead, assign the value outside the class (usually in your cpp file)
template<typename T>
struct Singleton {
static T *p;
static T *getInstance() { /*...*/ return p; }
};
template<typename T>
T *Singleton<T>::p = 0;
The interesting question is not the one you ask, but rather the opposite:
Why are const integral static members allowed to be assigned a value in the declaration?
The important bit of the question is declaration. The value that a variable gets is set in the variable definition, and that is consistent with non-const or non-integral static members of a class, where in the class you only offer a declaration. The initializer value is provided in the definition that is outside of the class definition, commonly in a .cpp that guarantees that it will be defined in a single translation unit.
But why can integral static constants have a value in the declaration?
For practical reasons. The compiler can use integral constants as compile-time constants, that is, it can actually replace the value of the constant in place of the identifier in all places where the constant is used as an rvalue, for example when defining the size of an array. But if the value is only present in the definition in a single translation unit, the compiler cannot possibly use it in all other translation units. As an example:
// fq.h
struct fixed_queue {
static const std::size_t max_elements; // [1]
int data[ max_elements ]; // Error: How big is data??
};
// fq.cpp
#include "fq.h"
const std::size_t fixed_queue::max_elements = 10;
If max_elements was not allowed to have a value in the declaration [1], then you would not be able to use that constant to define the size of the array data, which is a quite sensible use for a static constant.
Why not extend this to all other cases?
Because it does not seem to make much sense... Providing the value in the class definition cannot be used by the compiler in any other circumstance, and thus it is not needed, so only integral constants need to be treated differently.
The reason is that non-integral, non-const values require a memory location.
const int can be handled statically by the compiler and built directly into certain machine instructions, floats and more exotic objects need somewhere to live because the machine instructions will only operate in terms of their address.
In principle, the language could have allowed this, but it would mean either generating extra objects and bloating the binary (ok for consts), or making life hard for the compiler writers for non-consts: redundant copies would have to be dropped to preserve the one-definition rule (this is what template instantinations have to do, by the way).