Suppose that I have a few inline constexpr variables (named as default_y and default_x) in a header file and I decided to move them to a class that they are completely related to and mark them static (cause it seems better in terms of design).
namespace Foo
{
inline constexpr std::streamsize default_size { 160 }; // not closely related to the class Bar
class Bar
{
public:
inline static constexpr std::uint32_t default_y { 20 }; // closely related to the class Bar
inline static constexpr std::uint32_t default_x { 20 }; // closely related to the class Bar
};
}
So the question is will this make a difference in terms of how and when they are initialized at the start of the program (and overall efficiency)? Will the inline keyword in this particular use case force the compiler to add some guard for these two variables and make accessing them slower? Or maybe because they're constexpr there is no need to do those stuff at runtime since their value can be retrieved from the read-only section of the executable and then be assigned to them at the start of the main thread?
I built the program once with inline static and once with static and there was no difference in the size of the binary compared to the previous solution so maybe the linker generated the exact same code (hopefully).
Placing static inline constexpr variables should not impact efficiency in any way. Due to constexpr they're const-initialized at compile time if it's possible. inline keyword here is helping you to initialize static variable inside the body of a class. You might find this material on the inline keyword interesting: https://pabloariasal.github.io/2019/02/28/cpp-inlining/
Related
From elsewhere I know that it's not possible in C++17 to declare a static constexpr data member without its immediate initialization (although yet elsewhere they use such example).
// --- in header ---
struct Data{
LPCTSTR str;
int i;
};
class C{
public:
static constexpr Data MyData; // VS complains: this requires an in-class initializer
};
// --- in implementation file ---
constexpr Data C::MyData={
_T("Hi"), 12345
};
My code must, for the time being, compile also in older Visual Studios where the lack of constexpr concept can easily be #defined as
#if _MSC_VER<=1600 // pre-C++11 compiler?
#define constexpr const
#endif
and suddenly the code base would be compatible with virtually anything from VS6 to VS2019. Correct me if the off-class initialization is allowed by means of some hidden command-line switch in Visual Studio.
So I came up with a workaround about whose validity I'm not sure. Unlike data members, static constexpr methods don't have to have an in-class body. So I do:
// --- in header ---
struct Data{
LPCTSTR str;
int i;
};
class C{
public:
static constexpr Data GetMyData();
};
// --- in implementation file ---
constexpr Data C::GetMyData(){
constexpr Data D={
_T("Hi"), 12345
};
return D;
}
I can then benefit from constexpr, yet still compile (with the help of the above #define) under older Visual Studios:
constexpr LPCTSTR Greeting=C::GetMyData().str;
and also surprisingly take the address of the returned object at run-time:
const Data *p=&C::GetMyData();
const LPCTSTR greeting=p->str;
which is great and desired in my app! But makes me worry about the address of what I have received? Is it the address of the object compiled into the resulting executable (and at run-time residing in the protected memory) or an address of a global variable created really at run-time? I of course want the earlier to occur when compiling under newer Visual Studios, whereas I don't care about the situation under pre-C++11 versions.
Thanks in advance.
The key point is that constexpr does not mean "exists only at compile time", but instead "can also be used at compile time. So as long as you don't access the constexpr variable in a way that requires the value to be accessible at compile-time, it can be treated as if it was a const.
In fact, with the code you posted, the only place where you ever see the benefits of constexpr is inside of the implementation file. Anywhere else, it has not choice but to be "degrated" to a regular const since resolving its value during compilation is impossible.
I think most of your questions can be cleared up by deconstructing the code a bit into an equivalent example:
// MyClass.h
class MyClass {
// static constexpr Data MyData;
static const Data MyData;
};
// MyClass.cpp
namespace {
constexpr Data MyDataValue = ...;
}
const Data MyData::MyData = MyDataValue;
// If you use MyData inside of the implementation file, it gets the conxtepr value.
void MyClass:foo() {
// std::array<float, MyClass::Data.some_member> some_array;
std::array<float, MyDataValue.some_member> some_array; // no problem
}
// Some_other_file.cpp
int foo() {
// That's fine, MyClass::Data will be resolved either at runtime or during lto.
return MyClass::Data.some_member;
}
int bar() {
std::array<float, MyClass::Data.some_member> some_array; // ERROR! Can't be resolved at compile time
}
So what's the point of being able to declare a static constexpr data member without its immediate initialization?
As long as you define it later inside a header before it's actually used, then everything is fine, which can sometimes come in handy. However, in your case, since you want to define the variable inside an implementation file, you create this two-tiered system where the member is constexpr in the implementation file, and const anywhere else.
All this to say: If all your delayed constexpr definitions are in implementation files like in your posted code, then just make them const, and use locally a constexpr in an anonymous namespace inside of the implementation file if you need it there. No need for the macro at all.
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.
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;
}
I am a bit confused by the inline variable introduced by C++17. What are the differences between inline variable and inline static variable? Also will this be affected by scope?
inline T var_no_scope;
inline static T static_var_no_scope;
namespace scope {
inline T var_scope;
inline static T static_var_scope;
}
Any explanation will be appreciated!
At namespace scope:
inline static seems to be equivalent to just static.
inline on variables only has effect when you define the same variable in several translation units. Since static restricts the variable to a single TU, you can't have more than one definition.
At class scope:
inline can only appear on static variables.
It has its normal effect, allowing you to initialize the variable directly in the header. Either:
struct A
{
inline static int a = 42;
};
Or:
struct A
{
static int a;
};
inline int A::a = 42;
At function scope:
inline is not allowed.
For me it becomes more interesting when it is a data members. In C++17 you can declare your static data members as inline. The advantage is that you don't have to allocate space for them in a source file. For example:
class A
{
// Omitted for brevity
static inline int b = 0;
};
So int A::b; can be removed from the source file.
inline is applicable to variables only with static storage duration.
All of the variables in your example have namespace scope, giving them static storage duration. Declaring them inline has no net effect if they are static.
A variable inside a class, struct or union only has static storage duration if it is declared static. Those varibles must be static if they are to be inline.
Great answer about inline variables and why we want to use them can be found here. In short inline variable allows to have multiple definition of a variable (even across multiple files), that will result in one variable in memory. This allow constexpr global variables in header files.
header.h
namespace constants
{
inline constexpr double P = 1.11;
}
Behavior is undefined when definitions have different values, but this shouldn't be a problem when multiplication of definitions occur only due to header file.
Others have pointed to a nice application in classes:
template<typename T>
struct C
{
static inline constexpr int c = 10;
};
And then you can reference this variable anywhere, e.g. with:
C<int>::c;
The inline static variable can be defined in the class definition and may specify an initializer. It does not need an out-of-class definition:
struct X
{
inline static int n = 1;
};
Inline variables eliminate the main obstacle to packaging C++ code as header-only libraries.
If you need to declare global variables that are shared between compilation units, declare them as inline variables in the header file.
Also will this be affected by scope?
Any of the following names declared at namespace scope have external linkage and also names declared without a namespace for external linkage including in multiple source files must be inline.
See this Example.
This link has valuable information about inline variables.
definition from c++ reference: citation: https://en.cppreference.com/w/cpp/language/inline
inline variable is defined as inline static keyword. Hence
inline static vartype yourvariablename // is a inline variable.
Interesting note about inline "A function defined entirely inside a class/struct/union definition, whether it's a member function or a non-member friend function, is implicitly an inline function if it is attached to the global module"(C++ 20)
Ok from personal experience here's why inline static is a really really big thing:
If all you need todo is initialize a static variable in a C++ file then you can remove the C++ file and use inline static initialization(but your code will require C++ 17 and up)
Initializing static variables in pre C++ 17 classname templates is just overly verbose. You would have to do something like:
template
class classname
{
static yourtype yourstaticvariable = yourvalue; // and you'll have to initialize it
};
template yourtype classname::yourstaticvariable = yourvalue;
OR with inline static you can just do:
template <class T>
class classname
{
static yourtype yourstaticvariable = yourvalue; // initialized
}
You can heavily exploit templates if you use inline static for initializing common things. Consider for instance the singleton where a inline static variable is perfect for tracking the instance and hence can be done in one file where before initializing the static variable would be painful. This becomes even more evident when you have multivariable templates.
You need less C++ include files and less lib projects if you exploit inline static for single C++ header. This can heavily trim down files in a big project.
But there some caveats with inline static:
You need C++ 17 and up
You have to pay attention to issues of putting your initialization in a .h file(which you probably want to do if you initialize with inline static). Although this isn't necessarily a inline static issue but the decision to potentially moving everything to a header could lead to possible issues like namespace collisions, reusing macros or other things if you not careful with your order of inclusion.
But overall it's a fantastic feature. When in doubt initialize with inline static and break the I need a c++ file to initialize a static variable pattern.
With C++17 we get inline variables.
One of the uses for them is to define constant fields in classes.
So what's the difference between these two constant definitions:
class MyClass {
static constexpr int myFirstVar = 10;
static const inline int mySecondVar = 100;
};
Of course constexpr makes myFirstVar implicitly inline.
What's the better choice here, to use constexpr or inline?
Note: when you don't need constness, then inline makes it easier. With constexpr you don't have that choice.
You don't have to specify an initializer for mySecondVar at the point of declaration. Nor is the initializer required to be constexpr itself.
This means that if we attempt to define myFirstVar like this:
class MyClass {
static constexpr int myFirstVar;
};
int MyClass::myFirstVar = 1;
Or like this:
#include <cstdlib>
class MyClass {
static constexpr int myFirstVar = rand();
};
It's ill-formed either way. constexpr semantics demand it and for a good reason.
The inline specifier approach allows us to include a static variable definition in the header itself, without the initializer being constexpr; or if the initializer is fairly complex it doesn't have to be in the class definition itself.
So this is a perfectly valid header in C++17:
#include <cstdlib>
class MyClass {
static const int mySecondVar;
};
inline const int MyClass::mySecondVar = rand();
The standard promises us that all translation units that include the header will see the same value for the variable, even though we won't know what it is until run-time.
It's mostly a library writers tool. Assume your library is header only. Then in the olden days, what were your options if you needed a static constant defined like this?
Well, you could have an object file shipped with your library. It will be compiled from a translation unit that contains just the constant definition. Now the library isn't header-only.
Or you could rely on inline functions instead. The inline variable effect can be achieved with the following:
class MyClass {
static inline int mySecondVar();
};
inline int MyClass::mySecondVar() {
static const int value = rand();
return value;
}
But it's hidden behind a wall of syntax, and masks what is essentially a constant, with a function call operator.