Consider a class like so:
template < class T >
class MyClass
{
private:
static T staticObject;
static T * staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works
...
template < class T >
T * MyClass<T>::staticPointerObject = NULL; // <-- cannot find symbol staticPointerObject.
I am having trouble figuring out why I cannot successfully create that pointer object.
The above code is all specified in the header, and the issue I mentioned is an error in the link step, so it is not finding the specific symbol.
"Cannot find symbol staticPointerObject" - this looks like a linker error message. Is it? (Details like this have to be specified in your question).
If it is, them most likely it happens because you put the definition(s) of your static member(s) into an implementation file (a .cpp file). In order for this to work correctly, the definitions should be placed into the header file (.h file).
Again, details like this have to be specified in your question. Without them it turns into a random guess-fest.
I suspect the reason your first example is the following (from the 2003 C++ std document). Note particularly the last sentence -- from your example, there seems to be nothing "that requires the member definition to exist".
14.7.1 Implicit instantiation [temp.inst] 1 Unless a class template specialization has been explicitly instantiated (14.7.2) or explicitly
specialized (14.7.3), the class template specialization is implicitly
instantiated when the specialization is referenced in a context that
requires a completely-defined object type or when the completeness of
the class type affects the semantics of the program. The implicit
instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or
default arguments, of the class member functions, member classes,
static data members and member templates; and it causes the implicit
instantiation of the definitions of member anonymous unions. Unless a
member of a class template or a member template has been explicitly
instantiated or explicitly specialized, the specialization of the
member is implicitly instantiated when the specialization is
referenced in a context that requires the member definition to exist;
in particular, the initialization (and any associated side-effects) of
a static data member does not occur unless the static data member is
itself used in a way that requires the definition of the static data
member to exist.
Your first "definition" of static member is but a declaration - here is a quote from the standard.
15 An explicit specialization of a
static data member of a template is a
definition if the declaration includes
an initializer; otherwise, it is a
declaration. [Note: there is no syntax
for the definition of a static data
member of a template that requires
default initialization. template<> X
Q::x; This is a declaration
regardless of whether X can be default
initialized (8.5). ]
The second definition should work. Are you sure you have everything available in one compilation unit? What is teh exact text of error message?
The following compiles/runs with g++ - all in one file
#include <iostream>
template < class T >
class MyClass
{
public:
static T staticObject;
static T * staticPointerObject;
};
template < class T >
T MyClass<T>::staticObject;
template < class T >
T * MyClass<T>::staticPointerObject = 0;
int main(int argc, char **argv)
{
int an_int = 5;
MyClass<int>::staticPointerObject = &an_int;
std::cout << *MyClass<int>::staticPointerObject << std::endl;
char a_char = 'a';
MyClass<char>::staticPointerObject = &a_char;
std::cout << *MyClass<char>::staticPointerObject << std::endl;
}
I have found two solutions. Neither of them are 100% what I was hoping for.
Explicitely initialize the specific instance, e.g.
int * MyClass<int>::staticPointerObject = NULL;
This is not convinient especially when I have a lot of different types.
Wrap the pointer inside the class, e.g.
template < class T >
class MyClass
{
private:
struct PointerWrapper
{
T * pointer;
PointerWrapper( void )
: pointer( NULL )
{ }
};
T staticObject;
PointerWrapper staticPointerObject;
};
...
template < class T >
T MyClass<T>::staticObject; // <-- works fine.
...
template < class T >
MyClass<T>::PointerWrapper MyClass<T>::staticPointerObject; // <-- works fine.
This is a bit of a hassle, but at least usable. Why is it I can instansiate a variable object but not a pointer to a variable object? If anything I would think I'd have more problems the other way around (the compiler knows ahead of time what a pointer looks like, but not what my object looks like).
If someone has a better answer I'd love to see it!
I use the following trick all the time. The idea is to put your static in a function, and access it only from that function. This approach also allows you to avoid the need to declare your static in a .cpp file -- everything can live in the .h file. Following your example code:
template < class T >
class MyClass
{
public:
static T * getObject() {
// Initialization goes here.
static T * object = NULL; // or whatever you want
return pointerObject;
}
};
Related
I just wrote a class with some static data members, but now I am getting errors about "undefined references". Why doesn't this work? What am I doing wrong?
_(Note: This is meant to be an entry to [Stack Overflow's C++ FAQ](https://stackoverflow.com/questions/tagged/c++-faq). If you want to critique the idea of providing an FAQ in this form, then [the posting on meta that started all this](https://meta.stackexchange.com/questions/68647/setting-up-a-faq-for-the-c-tag) would be the place to do that. Answers to that question are monitored in the [C++ chatroom](https://chat.stackoverflow.com/rooms/10/c-lounge), where the FAQ idea started out in the first place, so your answer is very likely to get read by those who came up with the idea.)_
To understand this, you should have a good understanding of compiling and linking, and the differences between declarations and definitions.
Consider the following class:
//In header file
class Example {
static bool exampleStaticMember;
};
Here, exampleStaticMember is declared but not defined. This means that if exampleStaticMember is used in a way that means that it must have an address then there must be a separate definition for it. In general, no declaration of a static data member in a class definition is a definition of that member.
The required declaration is usually put in the cpp file which contains the other definitions for the members of the class. It must be in the same namespace as the class definition. The definition typically looks like:
//In source file:
//This may optionally have an initialiser (eg "= true")
bool Example::exampleStaticMember;
The definition can be put in any cpp file, but it should not be put in the header with the class, because that would be likely to break the One Definition Rule.
As a special case, if the static member variable is an const integral or enumeration type then it can have an initialiser in the class definition:
//In header file
class Example {
static const int initialised = 15;
};
In this case, the definition in the cpp file is still required, but it is not allowed to have an initialiser:
//In source file
//Note: no initialiser!
const int Example::initialised;
Static members that have been initialised like this can be used in constant expressions.
Templates
For a static data member of a template, things are slightly different. The static member should be defined in the header along with the rest of the class:
//In header file
template<typename T>
class Example {
static int exampleInt;
static T exampleT;
}
template<typename T> int Example<T>::exampleInt;
template<typename T> T Example<T>::exampleT;
This works because there is a specific exception to the One Definition Rule for static data members of class templates.
Other uses of static
When the static keyword is applied to functions and objects that are not in a class scope it can take on a very different meaning.
When applied to objects in a function scope, it declares an object that is initialised in the first execution of the function and that subsequently keeps its value between function calls.
When applied to objects or functions at namespace scope (outside of any class or function definition), it declares objects or functions with internal linkage. This usage is deprecated for objects, as the unnamed-namespace provides a better alternative.
You have to instantiate static members defined in a header in a .cpp file. For example:
// foo.h
class foo {
static int X;
};
// foo.cpp
#include "foo.h"
int foo::X = 0;
The following code fails to compile as expected:
#include<iostream>
class Enclosing {
int x;
class Nested { int y; };
void EnclosingFun(Nested *n) {
std::cout << n->y; // Compiler Error: y is private in Nested
}
};
However, if I change EnclosingFun into a template member function, the compiler (gcc-7) doesn't complain about accessing y:
#include<iostream>
class Enclosing {
int x;
class Nested { int y; };
template <typename T>
void EnclosingFun(Nested *n, T t) {
std::cout << t << n->y; // OK? Why?
}
};
Is this a bug in gcc? Or does c++ have different access rules for template member function to access nested classes?
Is this a bug in gcc? Or does c++ have different access rules for template member function to access nested classes?
No either.
According to the standard, ยง17.8.1 Implicit instantiation [temp.inst],
An implementation shall not implicitly instantiate a function template, a variable template, a member template, a non-virtual member function, a member class, a static data member of a class template, or a substatement of a constexpr if statement ([stmt.if]), unless such instantiation is required.
That means, Enclosing::EnclosingFun() is not instantiated here. Adding the invocation to it would cause it to be instantiated, then you'll get the error, e.g.
prog.cc:8:30: error: 'int Enclosing::Nested::y' is private within this context
std::cout << t << n->y; // OK? Why?
~~~^
LIVE
It is not a bug in GCC. You do not call your function template, therefore the function is not instantiated, and it does not try to access the private member of the nested class. Try to call your function somewhere in a real function (not template) or try to refer it (implicit instantiation).
A function template by itself is not a type, or a function, or any other entity. No code is generated from a source file that contains only template definitions. In order for any code to appear, a template must be instantiated: the template arguments must be determined so that the compiler can generate an actual function (or class, from a class template).
When code refers to a function in context that requires the function definition to exist, and this particular function has not been explicitly instantiated, implicit instantiation occurs.
template void Enclosing::EnclosingFun(Enclosing::Nested *n, int t); // instantiates the function for the second int parameter
I have two test cases of a class having a static member instance. The first uses non-templated samples, while the second relies on generic object types.
The dilemma is simple: the constructor of the static member gets called before the main function (as it should), but only for the specific object types. The generic types do not exhibit the same behaviour. As the matter of fact, the constructor isn't compiled at all. It seems the compiler decided to completely overlook it as a means of (not completely justified) optimization.
I would like to know what is happening and what can be done to make it work in the most elegant way possible. I presume the obvious answer would be: use that static member somewhere in the code. I'd like not to do that, as the specific type case works without making use of that static member, apart from performing some "work" in its constructor.
The code samples:
//////////////////////////////////////////////
// Specific case
//////////////////////////////////////////////
class CPassive
{
public:
CPassive()
{
printf(" passively called ");
}
};
class CActive
{
private:
static CPassive ms_passive;
};
CPassive CActive::ms_passive;
///////////////////////////////////////////////////////////
// GENERIC TYPES
///////////////////////////////////////////////////////////
class CSample
{
public:
CSample()
{
printf("sample ");
}
};
template <typename T>
class CGenericPassive
{
public:
CGenericPassive()
{
T sample;
printf(" generic passive .. ");
}
private:
};
template <typename T>
class CGenericActive
{
private:
static CGenericPassive<T> ms_passive;
};
template<typename T>
CGenericPassive<T> CGenericActive<T>::ms_passive;
int main(int argc, char** argv)
{
CActive activeExample;// instantiates the static member
CGenericActive<CSample> activeExample; // obliterates the static from the class def.
}
Each (non-virtual) member of each class template you want instantiated needs to be referenced from non-template code, directly or indirectly. It is not enough to instantiate the class itself.
This is governed by the standard 14.7.1/2:
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
In your case it is enough to reference the member from CGenericActive constructor (you need to write this constructor obviously), like this:
CGenericActive()
{
// just reference it so it gets instantiated
(void)ms_passive;
}
Full live example.
Consider the following code
#include <iostream>
using namespace std;
struct Printer{
Printer(){
std::cout << "Created\n";
}
};
template<class Derived>
struct InitPrinter{
static Printer p;
};
template<class Derived>
Printer InitPrinter<Derived>::p;
struct MyClass:InitPrinter<MyClass>{
MyClass(){}
};
// Uncomment line below to print out created
//auto& p = MyClass::p;
int main() {
return 0;
}
I expected that this would print out "Created", however, it does not print out anything (tested with MSVC and with ideone gcc c++11). Is this a compiler implementation issue, or is this behavior supported by the standard? If the commented out line is uncommented then it prints out as expected. Is there any way to the static Printer p to be instantiated without requiring either changes to MyClass or extra statements like the auto& p = MyClass::p?
The reason I am interested in this is I am looking to have create a templated base class, that will run some code at startup when it is derived from.
The appropriate quote is [temp.inst]/2
Unless a member of a class template or a member template has been explicitly instantiated or explicitly
specialized, the specialization of the member is implicitly instantiated when the specialization is referenced
in a context that requires the member definition to exist; in particular, the initialization (and any associated
side-effects) of a static data member does not occur unless the static data member is itself used in a way
that requires the definition of the static data member to exist.
emphasis mine.
There's also [temp.inst]/1
The implicit instantiation of a class template specialization causes the implicit
instantiation of the declarations, but not of the definitions or default arguments, of the class member functions, member classes, scoped member enumerations, static data members and member templates [...]
and [temp.inst]/10
An implementation shall not implicitly instantiate a function template, [...] or a static data member of a class template that does not require instantiation.
For static member initialization I use a nested helper struct, which works fine for non templated classes.
However, if the enclosing class is parameterized by a template, the nested initialization class is not instantiated, if the helper object is not accessed in the main code.
For illustration, a simplified example (In my case, I need to initialize a vector).
#include <string>
#include <iostream>
struct A
{
struct InitHelper
{
InitHelper()
{
A::mA = "Hello, I'm A.";
}
};
static std::string mA;
static InitHelper mInit;
static const std::string& getA(){ return mA; }
};
std::string A::mA;
A::InitHelper A::mInit;
template<class T>
struct B
{
struct InitHelper
{
InitHelper()
{
B<T>::mB = "Hello, I'm B."; // [3]
}
};
static std::string mB;
static InitHelper mInit;
static const std::string& getB() { return mB; }
static InitHelper& getHelper(){ return mInit; }
};
template<class T>
std::string B<T>::mB; //[4]
template<class T>
typename B<T>::InitHelper B<T>::mInit;
int main(int argc, char* argv[])
{
std::cout << "A = " << A::getA() << std::endl;
// std::cout << "B = " << B<int>::getB() << std::endl; // [1]
// B<int>::getHelper(); // [2]
}
With g++ 4.4.1:
[1] and [2] commented:
A = Hello, I'm A.
Works as intended
[1] uncommented:
A = Hello, I'm A.
B =
I would expect, that the InitHelper initializes mB
[1] and [2] uncommented:
A = Hello, I'm A.
B = Hello, I'm B.
Works as intended
[1] commented, [2] uncommented:
Segfault in the static initialization stage at [3]
Thus my question: Is this a compiler bug or is the bug sitting between the monitor and the chair?
And if the latter is the case: Is there an elegant solution (i.e. without explicitly calling a static initialization method)?
Update I:
This seems to be a desired behavior (as defined in the ISO/IEC C++ 2003 standard, 14.7.1):
Unless a member of a class template or a member template has been explicitly instantiated or explicitly specialized, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist; in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.
This was discussed on usenet some time ago, while i was trying to answer another question on stackoverflow: Point of Instantiation of Static Data Members. I think it's worth reducing the test-case, and considering each scenario in isolation, so let's look at it more general first:
struct C { C(int n) { printf("%d\n", n); } };
template<int N>
struct A {
static C c;
};
template<int N>
C A<N>::c(N);
A<1> a; // implicit instantiation of A<1> and 2
A<2> b;
You have the definition of a static data member template. This does not yet create any data members, because of 14.7.1:
"... in particular, the initialization (and any associated side-effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist."
The definition of something (= entity) is needed when that entity is "used", according to the one definition rule which defines that word (at 3.2/2). In particular, if all references are from uninstantiated templates, members of a template or a sizeof expressions or similar things that don't "use" the entity (since they are either not potentially evaluating it, or they just don't exist yet as functions/member functions that are itself used), such a static data member is not instantiated.
An implicit instantiation by 14.7.1/7 instantiates declarations of static data members - that is to say, it will instantiate any template needed to process that declaration. It won't, however, instantiate definitions - that is to say, initializers are not instantiated and constructors of the type of that static data member are not implicitly defined (marked as used).
That all means, the above code will output nothing yet. Let's cause implicit instantiations of the static data members now.
int main() {
A<1>::c; // reference them
A<2>::c;
}
This will cause the two static data members to exist, but the question is - how is the order of initialization? On a simple read, one might think that 3.6.2/1 applies, which says (emphasis by me):
"Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit."
Now as said in the usenet post and explained in this defect report, these static data members are not defined in a translation unit, but they are instantiated in a instantiation unit, as explained at 2.1/1:
Each translated translation unit is examined to produce a list of required instantiations. [Note: this may include instantiations which have been explicitly requested (14.7.2). ] The definitions of the required templates are located. It is implementation-defined whether the source of the translation units containing these definitions is required to be available. [Note: an implementation could encode sufficient information into the translated translation unit so as to ensure the source is not required here. ] All the required instantiations are performed to produce instantiation units. [Note: these are similar to translated translation units, but contain no references to uninstantiated templates and no template definitions. ] The program is ill-formed if any instantiation fails.
The Point of Instantiation of such a member also does not really matter, because such a point of instantiation is the context link between an instantiation and its translation units - it defines the declarations that are visible (as specified at 14.6.4.1, and each of those point of instantiations must give instantiations the same meaning, as specified in the one definition rule at 3.2/5, last bullet).
If we want ordered initialization, we have to arrange so we don't mess with instantiations, but with explicit declarations - this is the area of explicit specializations, as these are not really different to normal declarations. In fact, C++0x changed its wording of 3.6.2 to the following:
Dynamic initialization of a non-local object with static storage duration is either ordered or unordered.
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.
This means to your code, that:
[1] and [2] commented: No reference to the static data members exist, so their definitions (and also not their declarations, since there is no need for instantiation of B<int>) are not instantiated. No side effect occurs.
[1] uncommented: B<int>::getB() is used, which in itself uses B<int>::mB, which requires that static member to exist. The string is initialized prior to main (at any case before that statement, as part of initializing non-local objects). Nothing uses B<int>::mInit, so it's not instantiated, and so no object of B<int>::InitHelper is ever created, which makes its constructor not being used, which in turn will never assign something to B<int>::mB: You will just output an empty string.
[1] and [2] uncommented: That this worked for you is luck (or the opposite :)). There is no requirement for a particular order of initialization calls, as explained above. It might work on VC++, fail on GCC and work on clang. We don't know.
[1] commented, [2] uncommented: Same problem - again, both static data members are used: B<int>::mInit is used by B<int>::getHelper, and the instantiation of B<int>::mInit will cause its constructor to be instantiated, which will use B<int>::mB - but for your compiler, the order is different in this particular run (unspecified behavior is not required to be consistent among different runs): It initializes B<int>::mInit first, which will operate on a not-yet-constructed string object.
The problem is that the defintions you give for the static member variables are templates too.
template<class T>
std::string B<T>::mB;
template<class T>
typename B<T>::InitHelper B<T>::mInit;
During compilation, this defines actually nothing, since T is not known. It is something like a class declaration or a template definition, the compiler does not generate code or reserve storage when it sees it.
The definition happens implicitly later, when you use the template class. Because in the segfaulting case you don't use B<int>::mInit, it is never created.
A solution would be explictly defining the needed member (without initializing it): Put somewhere source file a
template<>
typename B<int>::InitHelper B<int>::mInit;
This works basically the same way as explictly defining a template class.
[1] uncommented case:
It is ok. static InitHelper B<int>::mInit does not exist. If member of the template class (struct) is not used it does not compiled.
[1] and [2] uncommented case:
It is ok. B<int>::getHelper() use static InitHelper B<int>::mInit and mInit exists.
[1] commented, [2] uncommented:
it works for me in VS2008.