Incomplete type as template argument

A

Andrew Ward

Hi All,

Considering the following code:

struct A;

struct B
{
std::list<A> l;
};

void foo()
{
B b;
};

struct A
{
int x;
};

int main()
{
foo();
A a;
a.x = 22;
B b;
b.l.push_back(a);
cout << "A's value = " << b.l.begin()->x << endl;
}

I do not understand why the compiler does not complain when encountered with std::list<A>
when A has not been fully defined.
Could someone please explain to me when the compiler actually does the template expansion,
and is this method of using incomplete types as template arguments safe for all compliant
compilers?

Andy
 
V

Victor Bazarov

Andrew Ward said:
Hi All,

Considering the following code:

struct A;

struct B
{
std::list<A> l;

Neither 'std' nor 'list' is defined.
};

void foo()
{
B b;
};

struct A
{
int x;
};

int main()
{
foo();
A a;
a.x = 22;
B b;
b.l.push_back(a);
cout << "A's value = " << b.l.begin()->x << endl;
}

I do not understand why the compiler does not complain when encountered
with std::list said:
when A has not been fully defined.

I do not understand either. Comeau C++ does complain.
Could someone please explain to me when the compiler actually does the template expansion,
and is this method of using incomplete types as template arguments safe for all compliant
compilers?

You should probably ask whoever made your compiler. They must hold
the secret of how to use an incomplete type as a template argument...

Victor
 
J

Jonathan Turkanis

Andrew Ward said:
Hi All,

Considering the following code:


I do not understand why the compiler does not complain when
encountered with std::list said:
when A has not been fully defined.
Could someone please explain to me when the compiler actually does the template expansion,
and is this method of using incomplete types as template arguments safe for all compliant
compilers?

This topic has been extensively discussed on comp.lang.c++.moderated
recently. (See "class definition containing member of own type",
etc. )

According to the language rules, it may well be possible to
instantiate std::list with an incomplete type (depending on the
implementation.) However, the library requirements specifically make
it undefined behaviour to instantiate a standard library template with
an incomplete type (17.4.3.6).

Presumably this will change, since one of the benefits of shared_ptr
is supposed to be that it can be instantiated with an incomplete type.
(I don't see anything about this in the TR1 draft, though.)

Jonathan
 
S

Sharad Kala

Andrew Ward said:
Hi All,

Considering the following code:

struct A;

struct B
{
std::list<A> l;
};

void foo()
{
B b;
};

struct A
{
int x;
};

int main()
{
foo();
A a;
a.x = 22;
B b;
b.l.push_back(a);
cout << "A's value = " << b.l.begin()->x << endl;
}

Which compiler?
Atleast VC 7, g++ 3.3.1 and Comeau online reject this code.

-Sharad
 
J

John Carson

Victor Bazarov said:
Neither 'std' nor 'list' is defined.


I do not understand either. Comeau C++ does complain.


You should probably ask whoever made your compiler. They must hold
the secret of how to use an incomplete type as a template argument...

Victor


I don't claim to understand all the subtleties of this matter but... section
14.3.1 p2 of the 2003 standard says:

"[Note: a template type argument may be an incomplete type (3.9). ]"
 
A

Andrew Ward

Sharad Kala said:
Which compiler?
Atleast VC 7, g++ 3.3.1 and Comeau online reject this code.

-Sharad

I am using VC 7.1, I am guessing from the responses though that this kind of code is not a
good idea for compatibility with other compilers. The reason I wanted to do this was
because I am trying to reduce the number of #includes in my header files, as to speed up
compiles when changes are made to the headers.
 
T

tom_usenet

Hi All,

Considering the following code:
[SNIP list said:
I do not understand why the compiler does not complain when encountered with std::list<A>
when A has not been fully defined.
Could someone please explain to me when the compiler actually does the template expansion,
and is this method of using incomplete types as template arguments safe for all compliant
compilers?

In general it is undefined behaviour to instantiate any standard
container type with an incomplete type parameter. However, it has also
been shown that an implementation of the standard library can
carefully be written so that it will work with an incomplete type -
the main things to do are to no have any nested types, e.g. make
vector::iterator a typedef for a non-nested type.

To understand why, you need to know a little bit about implicit
instantiation. A class template specialization isn't instantiated
until it is used in a context that requires a completely defined
object type. So:

typedef mytemplate<int> t; //no instantiation
mytemplate<int> t; //no instantiation
sizeof(mytemplate<int>); //instantiation
mytemplate<int> t; //instantiation, possibly also of default
constructor

Now, when a class template definition is instantiated, any types that
need to be complete in the class definition are also instantiated.
e.g.

template <class T>
struct Foo
{
Bar<T> bar; //member, so instantiated
Baz<T>* baz; //pointer, so not instantiated
class Inner //member, so instantated
{
char array[sizeof(Baz<T>)]; //Baz<T> instantiated
};
};


So once you understand those rules, consider how std::list might be
implemented (ignoring the allocator parameter)

template <class T>
class list
{
struct Node
{
//boom, requires T to be complete
//when list<T> is instantiated
T value;
Node* prior;
Node* next;
};
//...
};

If you take the node type out, then you have:

template <class T>
struct ListNode
{
T value;
ListNode* prior;
ListNode* next;
};

template <class T>
class list
{
//doesn't instantiate ListNode<T> when list<T> is instaniated
typedef ListNode<T> node_t;
//doesn't instantiate ListNode<T>
node_t* node;
//... etc
};

GCC allows use of all containers with incomplete types. Dinkumware
have finally updated their library to do the same, and VC7.1 benefits.
Many other compilers (including earlier versions of MSVC) don't allow
incomplete types. Perhaps a future standard will guarantee that
containers can be instantiated with incomplete types, but don't hold
your breath.

Tom
 

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,014
Latest member
BiancaFix3

Latest Threads

Top