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).
Related
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).
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.
In the following library code:
#include <cmath>
namespace blah {
const double pi=4.0*std::atan(1.0);
}
template <int I>
class ClassB
{
public:
ClassB() {myval = blah::pi;}
private:
double myval;
};
template <int I>
class ClassA
{
public:
static ClassB<I> b;
};
template<int I>
ClassB<I> ClassA<I>::b = ClassB<I>();
template class ClassA<3>;
is the variable pi guaranteed by the standard to be assigned to its value 4.0*std::atan(1.0) before the constructor of ClassB uses it?
As far as I can tell from the standard, pi and static ClassA<I>::ClassB<I> b should be initialised in the order in which they are defined in this single translation unit - and thus pi should be initialised first.
However, in my real codebase with the code structure as above, I am finding that in code compiled by Clang 3.6, pi is equal to zero at the time that the ClassB constructor is executed, and is initialised to its proper value only after this.
(GCC 4.8.3 initialises pi first, as I was expecting.)
The simple answer is no. There are no guarantees. If ClassB<I> ClassA<I>::b = ClassB<I>() were not a template, there would be a guarantee, since both are in the same translation unit, but that guarantee ceases to exist if the static is member of a template class (presumably because the actual instantiation could be in any translation unit).
In this particular case, however: why the convoluted way of getting a constant pi. Just:
double const pi = 3.1415926535897932384626433832795;
should be enough. (If you've any doubts for any of the target machines, then add more digits. But this is more than is needed to get the most accurate representation possible for IEEE.) And because this is static initialization, it is guaranteed to occur before any dynamic initialization takes place.
As James Kanze says, the answer is no, the order cannot be guaranteed (even though ClassA<3> is explicitly instantiated within the translation unit). This answer provides more detail on the problem.
One solution is to is to specialise the static member variable in the library .cpp file, with
template<>
ClassB<3> ClassA<3>::b = ClassB<3>();
rather than instantiating the template with template class ClassA<3>;.
The C++03 spec. doesn't spell this out explicitly, but the C++11 spec. is clearer on the issue:
Definitions of explicitly specialized
class template static data members have ordered initialization.
Other class template static data members (i.e., implicitly
or explicitly instantiated specializations) have unordered
initialization.
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!)
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!)