Initialization of static varible in class template

D

Drew McCormack

I have a C++ template class which contains a static variable whose
construction registers the class with a map. Something like this:

template <typename T>
class M {
static Registrar<M> registrar;
};

The constructor of Registrar does the registering when it is initialized.

My problem is, I can't get this to work for a general class M<T>. I can
get it to work for a specific instance, like M<double>, by including the
initialization definition in the .cpp file:

Registrar< M<double> > M<double>::registrar;

but the general case doesn't work:

template <typename T>
Registrar< M<T> > M<T>::registrar;

It doesn't matter where I put this code --- in the header or .cpp file
--- the Registrar constructor does not get called.

Can anyone tell me where I should put the definition, and whether I need
to do something special with gcc (v3.3) options?

Drew
 
V

Victor Bazarov

Drew said:
I have a C++ template class which contains a static variable whose
construction registers the class with a map. Something like this:

template <typename T>
class M {
static Registrar<M> registrar;
};

The constructor of Registrar does the registering when it is initialized.

My problem is, I can't get this to work for a general class M<T>. I can
get it to work for a specific instance, like M<double>, by including the
initialization definition in the .cpp file:

Registrar< M<double> > M<double>::registrar;

but the general case doesn't work:

template <typename T>
Registrar< M<T> > M<T>::registrar;

It doesn't matter where I put this code --- in the header or .cpp file
--- the Registrar constructor does not get called.

Can anyone tell me where I should put the definition, and whether I need
to do something special with gcc (v3.3) options?

All you need to do is use that 'registrar' somehow. If it's not used,
it's not created. 14.7.1/7 says "The implicit instantiation of a class
template does not cause any static data members of that class to be
implicitly instantiated."

What works, as you described, is the _explicit_ instantiation. Implicit
one doesn't.

As to gcc options, please ask in a gcc newsgroup. Compiler options are
off-topic here.

Victor
 
D

Drew McCormack

Hi Victor,
You were right, I needed to use the static variable in my code.
Nonetheless, I am a bit confused as to why this is necessary. Here is why:
All you need to do is use that 'registrar' somehow. If it's not used,
it's not created. 14.7.1/7 says "The implicit instantiation of a class
template does not cause any static data members of that class to be
implicitly instantiated."
I do explicitly instantiate the class template: I use M<double> in my
code, for example. What I wasn't doing is using the static variable
explicitly. Should this be necessary, or is explicitly instantiating the
class template enough?

Drew
 
D

Drew McCormack

Victor said:
All you need to do is use that 'registrar' somehow.
One more question: Do you have any suggestions for a clean way to use
the registrar instance in order to force the compiler to create it? At
the moment I am just calling a method of registrar that does nothing
inside the destructor of M<T>, but maybe there is a cleaner way to do it.

Drew
 
V

Victor Bazarov

Drew said:
Hi Victor,
You were right, I needed to use the static variable in my code.
Nonetheless, I am a bit confused as to why this is necessary. Here is why:


I do explicitly instantiate the class template: I use M<double> in my
code, for example.

Didn't you initially say that you only had a problem with non-specialised
(not explicitly instantiated) variations of the template? I took it that
What I wasn't doing is using the static variable
explicitly. Should this be necessary, or is explicitly instantiating the
class template enough?

It's enough to explicitly instantiate the class. But was it the problem
you were running into?

Victor
 
V

Victor Bazarov

Drew said:
One more question: Do you have any suggestions for a clean way to use
the registrar instance in order to force the compiler to create it? At
the moment I am just calling a method of registrar that does nothing
inside the destructor of M<T>, but maybe there is a cleaner way to do it.

What is the purpose of the registrar? Do you intend in the future to
query it somehow to find out how many instances/classes have been created
in the program? If you do query it, you will get your "use" and it will
be instantiated. Until then, put debugging its constructor aside.

Victor
 
D

Drew McCormack

Victor said:
What is the purpose of the registrar? Do you intend in the future to
query it somehow to find out how many instances/classes have been created
in the program? If you do query it, you will get your "use" and it will
be instantiated. Until then, put debugging its constructor aside.

Victor
The registrar registers the class in a map, which is used for
serialization. The registrar constructor does this, and it needs to do
it once for each registered class. By including a static instance of
registrar in each class, I intend that the registrar registers the
class, inserting it in the map, before the main program starts.
 
D

Drew McCormack

Victor said:
Didn't you initially say that you only had a problem with non-specialised
(not explicitly instantiated) variations of the template? I took it that




It's enough to explicitly instantiate the class. But was it the problem
you were running into?

Victor
It works if I explicitly instantiate the static variable:

M<double>::registrar;

But it doesn't work if I just explicitly instantiate the class M:

M<double> mInstance;

The latter does not lead to the static M<double>::registrar being
created. I thought it should, but it doesn't.

Drew
 
V

Victor Bazarov

Drew said:
It works if I explicitly instantiate the static variable:

M<double>::registrar;

But it doesn't work if I just explicitly instantiate the class M:

M<double> mInstance;

The latter does not lead to the static M<double>::registrar being
created. I thought it should, but it doesn't.

I think you're confused what is an instantiation of what. When you write

M<double> mInstance;

it's an [explicit] instantiation of the class M<double>, but it's not
an explicit instantiation of the template. For the template, it's very
_implicit_. An explicit instantiation of the template would be

template class M<double>;

Yes, it's supposed to work when you explicitly initialise the static data
member itself. However, it should also work when you instantiate the
template explicitly, without explicit instantiation of the static data
member. Example:

template<class T> struct A { static int sa; }; // template definition
template<class T> int A<T>::sa; // definition of the static member

// the following is the explicit instantiation of A<int>
template struct A<int>; // causes A<int>::sa to be instantiated, no
// matter whether you ever have an object of
// type A<int>

// the following is an explicit instantiation of A<char>::sa
template int A<char>::sa;

// the following is an implicit instantiation of A<double> _and_
// an [explicit] instantiation of an object of A<double> type.
A<double> ad; // does NOT instantiate A<double>::sa

What you need to distinguish here is instantiating a template and that
of the resulting class. When you instantiate a class, you create one
object (instance) of that class, which allocates some memory, etc. But
it doesn't cause any code to be created. When you instantiate a template,
the code for _functions_ is created and also static data members are
created (instantiated).

Victor
 
D

Drew McCormack

Victor said:
Drew said:
It works if I explicitly instantiate the static variable:

M<double>::registrar;

But it doesn't work if I just explicitly instantiate the class M:

M<double> mInstance;

The latter does not lead to the static M<double>::registrar being
created. I thought it should, but it doesn't.


I think you're confused what is an instantiation of what. When you write

M<double> mInstance;

it's an [explicit] instantiation of the class M<double>, but it's not
an explicit instantiation of the template. For the template, it's very
_implicit_. An explicit instantiation of the template would be

template class M<double>;

Yes, it's supposed to work when you explicitly initialise the static data
member itself. However, it should also work when you instantiate the
template explicitly, without explicit instantiation of the static data
member. Example:

template<class T> struct A { static int sa; }; // template definition
template<class T> int A<T>::sa; // definition of the static member

// the following is the explicit instantiation of A<int>
template struct A<int>; // causes A<int>::sa to be instantiated, no
// matter whether you ever have an object of
// type A<int>

// the following is an explicit instantiation of A<char>::sa
template int A<char>::sa;

// the following is an implicit instantiation of A<double> _and_
// an [explicit] instantiation of an object of A<double> type.
A<double> ad; // does NOT instantiate A<double>::sa

What you need to distinguish here is instantiating a template and that
of the resulting class. When you instantiate a class, you create one
object (instance) of that class, which allocates some memory, etc. But
it doesn't cause any code to be created. When you instantiate a template,
the code for _functions_ is created and also static data members are
created (instantiated).

Victor
OK, now I get it. Thanks. I wasn't up with the explicit/implicit
definitions. Thanks for making that clear.

Cheers,
Drew
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top