C++ Templates book

F

Fraser Ross

On P304 the book seems to be suggesting that static data members of a
class template have separate objects for every parameter that
instantiates the template. It says on P97 that they are much like
ordinary class members. I think someone was mistaken while writing
P304. Does anyone agree?

Fraser.
 
A

Alf P. Steinbach

* Fraser Ross:
On P304 the book seems to be suggesting that static data members of a
class template have separate objects for every parameter that
instantiates the template.

Yes.

When you instantiate a class template you get a concrete class.

Each concrete class has its own static data members.

It says on P97 that they are much like
ordinary class members.
Yes.


I think someone was mistaken while writing
P304. Does anyone agree?

Not on the basis of what you describe above.

By the way, it's very simple to test such things.

Saves you much time.

Also, by the way, it's good idea to be clear about which book, edition etc.
you're talking about.

I'm *guessing* that the book in question is the one by Josuttis and Vandevoorde
-- is it?


Cheers & hth.,

- Alf
 
F

Fraser Ross

Alf P. Steinbach said:
* Fraser Ross:

Yes.

When you instantiate a class template you get a concrete class.

Each concrete class has its own static data members.

Is this both when the statics type is a class template parameter and
when it is not? I think it is only the former case.

Fraser.
 
P

peter koch

Is this both when the statics type is a class template parameter and
when it is not?  I think it is only the former case.

Fraser.

It is any case. Two template instantiations are completely unrelated.

/Peter
 
F

Fraser Ross

P97 has this class:

template <int I>
class CupBoard {
static double weight;
};

template <int I>
double CupBoard<I>::weight = 0.0;

Is this a definition of weight for all instantiations? Wouldn't that
mean it is x number of definitions?

Fraser.
 
F

Fraser Ross

P97 has this class:
template <int I>
class CupBoard {
static double weight;
};

template <int I>
double CupBoard<I>::weight = 0.0;

Is this a definition of weight for all instantiations? Wouldn't that
mean it is x number of definitions?

I understand it now. x number of instances have a definition of weight
at the same point in the source code.

Fraser.
 
F

Fraser Ross

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<2> a2;
A<1> a1;

int main() {
A<1>::c; A<2>::c;
}

I copied this from the moderated group. Why is it necessary to have the
given code in the main function to get an output from Cs constructor?
Is the compiler allowed to forego the creation of a1 and a2 since they
are not required for the program? I have tried this program with all
optimisations off and I still need the code in the constructor.

Fraser.
 
A

Alf P. Steinbach

* Fraser Ross:
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<2> a2;
A<1> a1;

int main() {
A<1>::c; A<2>::c;
}

I copied this from the moderated group. Why is it necessary to have the
given code in the main function to get an output from Cs constructor?
Is the compiler allowed to forego the creation of a1 and a2 since they
are not required for the program? I have tried this program with all
optimisations off and I still need the code in the constructor.

Consider the following code:

template< typename T >
struct X
{
void foo() { T().trallala(); }
void bar() {}
};

int main()
{
X<void>();
}

This should compile fine with any compiler, even though 'void' is not a class
type, and certainly is not one with a member function 'trallala'.

It's allowed because *if* class X is instantiated with T some class type with a
'trallala' member, then 'foo' can be used for that instantiation.

In short with a class template only what's used is instantiated (although if you
have syntax errors or other ordinary C++ errors such as zero-size array, or
refer to non-existing things that do not depend on a template parameter, then
compilation of the template itself will fail, before anything's instantiated).

At this point check to see if you can't make sense of the behavior you've
observed! :)

But there is a more subtle thing. With MSVC the output is 2,1, whereas with
MinGW g++ 3.4.5 the output is 1,2. I'm not quite sure what the standard has to
say about this, if anything, but it doesn't matter much because if you rely on
any specific order for such a subtle feature (dark corner of the language), then
you're doomed: the main rule is the stay away from those dark corners unless you
absolutely have to, because both compilers and other programmers get confused.


Cheers & hth.,

- Alf
 
F

Fraser Ross

"Alf P. Steinbach"
* Fraser Ross:

Consider the following code:

template< typename T >
struct X
{
void foo() { T().trallala(); }
void bar() {}
};

int main()
{
X<void>();
}

This should compile fine with any compiler, even though 'void' is not
a class type, and certainly is not one with a member function
'trallala'.

It's allowed because *if* class X is instantiated with T some class
type with a 'trallala' member, then 'foo' can be used for that
instantiation.

In short with a class template only what's used is instantiated
(although if you have syntax errors or other ordinary C++ errors such
as zero-size array, or refer to non-existing things that do not depend
on a template parameter, then compilation of the template itself will
fail, before anything's instantiated).

I don't see what the relevance is. Struct A doesn't have anything to
not instantiate.


But there is a more subtle thing. With MSVC the output is 2,1, whereas
with MinGW g++ 3.4.5 the output is 1,2. I'm not quite sure what the
standard has to say about this, if anything, but it doesn't matter
much because if you rely on any specific order for such a subtle
feature (dark corner of the language), then you're doomed: the main
rule is the stay away from those dark corners unless you absolutely
have to, because both compilers and other programmers get confused.


Static initialisation order is not a dark corner to me since I've looked
at it quite recently. There are four objects with static
initialisation: a1, a2, A<2>::c and A<1>::c. I'm not sure what the
order is between A<2>::c and A<1>::c. The order with a1 and a2 is
implementation defined according to 3.6.2/4.

Fraser.
 
F

Fraser Ross

"Alf P. Steinbach"
Huh, don't u c?

I c now.

a2 and a1 have ordered initialisation and a2 is first. A<2>::c and
A<1>::c don't have ordered initialisation.

Fraser.
 
J

James Kanze

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<2> a2;
A<1> a1;
int main() {
A<1>::c; A<2>::c;
}
I copied this from the moderated group. Why is it necessary
to have the given code in the main function to get an output
from Cs constructor?

Because the compiler is only allowed to instantiate the parts of
a class template which are actually used. (On the other hand,
you don't need the definitions of a1 and a2.)
Is the compiler allowed to forego the creation of a1 and a2
since they are not required for the program?

It is required to forego them.
 
J

James Kanze

* Fraser Ross:

[...]
But there is a more subtle thing. With MSVC the output is 2,1,
whereas with MinGW g++ 3.4.5 the output is 1,2. I'm not quite
sure what the standard has to say about this,

It says that the order of initialization is unspecified.
if anything, but it doesn't matter much because if you rely on
any specific order for such a subtle feature (dark corner of
the language), then you're doomed: the main rule is the stay
away from those dark corners unless you absolutely have to,
because both compilers and other programmers get confused.

That's very good advice, in general (and in this particular
case). But taken too literally, it means no templates, because
name lookup in templates would certainly qualify as a dark
corner of the language:).
 
J

James Kanze

"Alf P. Steinbach"

[...]
I don't see what the relevance is. Struct A doesn't have
anything to not instantiate.

It has a static data member c.
Static initialisation order is not a dark corner to me since
I've looked at it quite recently. There are four objects with
static initialisation: a1, a2, A<2>::c and A<1>::c. I'm not
sure what the order is between A<2>::c and A<1>::c. The order
with a1 and a2 is implementation defined according to 3.6.2/4.

The order of initialization of a1 and a2 is well defined, with
a2 initialized before a2. (Of course, in the existing code,
there's no way you can tell.) But except for such trivial cases
(and the case of a static local variable), I'd agree with Alf
that you're playing with fire if you count on anything:
basically, variables defined at namespace scope in the same are
initialized in the order of definition, static variables with
block scope are initialized the first time execution passes over
the definition, and the rest is unspecified. (And of course,
the statement:
template<int N> C A<N>::c(N);
doesn't define a variable. So it isn't covered by the
"variables defined at namespace scope".)
 
F

Fraser Ross

The order of initialization of a1 and a2 is well defined, with
a2 initialized before a2. (Of course, in the existing code,
there's no way you can tell.) But except for such trivial cases
(and the case of a static local variable), I'd agree with Alf
that you're playing with fire if you count on anything:
basically, variables defined at namespace scope in the same are
initialized in the order of definition, static variables with
block scope are initialized the first time execution passes over
the definition, and the rest is unspecified. (And of course,
the statement:
template<int N> C A<N>::c(N);
doesn't define a variable. So it isn't covered by the
"variables defined at namespace scope".)

I don't think c is at namespace scope - its at class scope. Where is
the static A<2>::c defined? Is it implicitly defined at the A<2>::a2;
statement? Also is it defined after A<2>::a2?

Fraser.
 
J

James Kanze

I don't think c is at namespace scope - its at class scope.

It depends on what aspect of c you're talking about. The
variable c has class scope---it's only "visible" in contexts
where members of the class are visible. The definition,
however, is lexically at namespace scope, and that's what
determines the order of initialization (for variable
definitions).
Where is the static A<2>::c defined? Is it implicitly defined
at the A<2>::a2; statement? Also is it defined after
A<2>::a2?

The "point of instantiation" of A<2>::c "immediately follows the
namespace scope declaration or definition that refers to the
specialization", i.e. in this case, immediately after the
function main().

If you actually defined a non-template variable (static member
or free variable) at that point, its initialization would be
ordered with respect to all other variables with static lifetime
defined in the module. In the case of the instantiation of a
static member of a template, however, the language removes this
guarantee, since such definition can, in fact, have many
different "points of instantiation", in different translation
units, and the authors of the standard didn't want to make a
special case for cases where the variable was in fact only
implicitely instatiated once.
 

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

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,296
Latest member
HeikeHolli

Latest Threads

Top