C++ templates and static members - definition in the header - c++

Consider the following construct:
//! Templated singleton.
/*!
Template wrapper enforcing the singleton behavior.
*/
template <class T>
class TSingleton
{
private:
//! Singleton instance pointer.
static T* instance;
//! private constructor.
TSingleton() { }
//! private empty copy constructor.
TSingleton(const TSingleton<T>& sourceObject) {}
public:
//! Static singleton instance getter.
static T* GetInstance()
{
if (instance == 0)
instance = new T();
return instance;
}
};
template <class T> T* TSingleton<T>::instance = 0;
This template class and the definition of the static instance are written in the same header file. For a non-template class, this causes a link-time error due to multiple symbols being defined for the instance static member. It seems intuitive for this to happen with templates as well, thus one must separate the definition and put it in a .cpp file. But templates are usually declared and defined in header-like files. What is it that allows this syntax to be valid and functional for template classes?
There a wikipedia link on this, but it does not provide a clear explanation on what happens in case of template classes.

This works because [basic.def.odr]/5 explicitly allowed templates to be duplicated:
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. ...
The requirements are quite lengthy, so I won't duplicate them here, but essentially they state that each duplicate definition must be identical (otherwise the program has undefined behaviour).

Related

Do templated ctor and methods need "inline" specifier if defined outside class? [duplicate]

Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.

Why are some functions within my template class not getting compiled?

I am using VS Express 2013 trying to compile a c++ project. I've created a template class with some functions. The class and its functions are all in one header file. I've included the file, I've used the class, I've called functions from it, and despite all that visual studio won't compile the classes' functions that I'm not using. I've turned off all optimizations. Do I HAVE to use a function that I've written just to see that it compiles or not?
Here is the function:
void remove(ID id)
{
sdfgsdfg456456456456sfdsdf
}
The function shouldn't compile. And indeed the project won't compile if I do use this function, but if I don't use the function the project will compile, even if I use other functions from within this class.
Is there a fix to this? Will the same thing happen if I implement the function in a .cpp file?
Edit: I neglected to mention it is a template class. I've added that information in.
As revealed in comments, the reason this is happening is because remove() is a function in a class template. The compiler only instantiates template code if it is actually used; if you don't call remove(), it can have all the syntax errors you want and nobody will complain.
More formally, § 14.7.1 of the standard states (emphasis mine):
The implicit instantiation of a class template specialization causes
the implicit instantiation of the declarations, but not the
definitions or default arguments, of the class member functions
And later in the same section:
An implementation shall not implicitly instantiate a function
template, a member template, a non-virtual member function, a member
class, or a static data member of a class template that does not
require instantiation.
(the word "implicit" is key here; if you use explicit template instantiation, the compiler will immediately try to instantiate all members using the indicated type(s) and fail if any doesn't compile)
This is not just an optimization; you can exploit this behavior to instantiate class templates with types that only support a subset of the template's operations. For example, suppose you write a template class that will be used with types that support a bar() operation, and in addition, some will also support baz(). You could do this:
template<typename T>
class Foo
{
private:
T _myT;
public:
void bar()
{
_myT.bar();
}
void baz()
{
_myT.baz();
}
};
Now suppose you have these too:
struct BarAndBaz
{
void bar() {}
void baz() {}
};
struct BarOnly
{
void bar() {}
};
This will compile and run just fine:
void f()
{
Foo<BarAndBaz> foo1;
foo1.bar();
foo1.baz();
Foo<BarOnly> foo2;
foo2.bar();
// don't try foo2.baz()!
// or template class Foo<BarOnly>!
}

Ensuring a static member of a class is constructed

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.

Template definitions outside class body

Is it O.K. to define virtual function of class template outside its body? Virtual function can not be inlined, but to avoid multiple definitions in compilation units they shall be marked inline (assuming that template headers will be included in multiple source files). On the other hand compiler is free to ignore inline, so this seems valid. By an example, is the code below correct:
template <typename T>
class C
{
public:
virtual void f(T val);
};
template <typename T>
inline
void C<T>::f(T val)
{
//definition
}
?
BTW gcc (3.4.2) allows to omit inline before definition of function f(T val) but not before analogous function of regular class. Is it only gcc's behaviour?
Yes, it's OK even without inline. It works the same for ordinary member functions and static variables:
// everything in the header:
template <class T>
class A
{
static int i;
};
template <class T>
int A<T>::i=0;
Standard quote: (3.2/5)
There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with
external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member
of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for
which some template parameters are not specified (14.7, 14.5.5) in a program provided that each definition
appears in a different translation unit, and provided the definitions satisfy the following requirements ...
The requirements basically say the two definitions have to be identical.
It doesn't work in case of regular classes. There has to be at most one definition in the whole program.
You can define template methods outside the class definition, in the same header, without using inline and without receiving multiple definition errors.
That's because a template function doesn't generate a definition itself, if it's not fully specialized. To prove my point, the following:
void C<int>::f(int)
{
}
will result in a linker error, as the function has a definition in this case. (provided you include this in multiple translation units. If you mark it inline:
inline void C<int>::f(int)
{
}
the error no longer occurs.
You can define the functions there, as long as any code which needs to instantiate the function in question has visibility of that code at compile time (not link time).
It's quite common to separate a template into 2 files, one being a traditional header, and the second being the implementation, as with non-templated functions and their implementation. The only difference is that you need to #include the template implementation file as well as the header when you want to use it.

Initializing static pointer in templated class

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;
}
};