Forward Declarations of types used in template container classes

S

Stephen Howe

Hi

I cant find whether this is valid C++, but I believe it is

// ---------------------------- start header file
#include <vector>

// Forward Declaration
class FooBar;

int SomeFunction1(FooBar); // Valid
declaration, I know this
int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
using std::vector???

// ---------------------------- end header file

Yes FooBar is incomplete but all I am interested in is whether it is a
valid declaration.
All of this is to minimise header file dependency, so FooBar's
definition is not dragged in.
I know that where SomeFunction2 is defined, a full definition of
FooBar is needed.

Thanks

Stephen Howe
 
V

Victor Bazarov

Hi

I cant find whether this is valid C++, but I believe it is

// ---------------------------- start header file
#include<vector>

// Forward Declaration
class FooBar;

int SomeFunction1(FooBar); // Valid
declaration, I know this
int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
using std::vector???

// ---------------------------- end header file

Yes FooBar is incomplete but all I am interested in is whether it is a
valid declaration.
All of this is to minimise header file dependency, so FooBar's
definition is not dragged in.
I know that where SomeFunction2 is defined, a full definition of
FooBar is needed.

Since in the context of the declaration of 'SomeFunction2' the full
definition of 'std::vector<FooBar>' is not required, it is not going to
be instantiated. If no instantiation happens, FooBar may be incomplete.
The declaration of 'SomFunction2' is legal, I suppose.

V
 
N

Noah Roberts

Hi

I cant find whether this is valid C++, but I believe it is

// ---------------------------- start header file
#include<vector>

// Forward Declaration
class FooBar;

int SomeFunction1(FooBar); // Valid
declaration, I know this

You do?
int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
using std::vector???

Yes.
 
A

Alf P. Steinbach /Usenet

* Victor Bazarov, on 08.04.2011 23:41:
Since in the context of the declaration of 'SomeFunction2' the full definition
of 'std::vector<FooBar>' is not required, it is not going to be instantiated. If
no instantiation happens, FooBar may be incomplete. The declaration of
'SomFunction2' is legal, I suppose.

Not formally.

C++98 §17.4.3.6/2, about standard library containers:
"In particular, the effects are undefined in the following cases:
[blah blah]
- if an incomplete type (3.9) is used as a template argument when
instantiating a template component"

That is, standard libary containers are special, in that the element type must
(formally) be complete.

A compiler is free to check, by any means, that the type is complete.

Doing such checking yourself might look like this:


<code>
namespace pedantic {

template< class Elem, int enforcedCompleteness = sizeof( Elem ) >
class Vector
{
// ...
};
}

// Forward Declaration
class FooBar;

int SomeFunction1( FooBar ); // Valid.
int SomeFunction2( pedantic::Vector<FooBar>& ref ); // Invalid.

int main()
{}
</code>


Cheers & hth.,

- Alf
 
P

Pavel

Alf said:
* Victor Bazarov, on 08.04.2011 23:41:
Since in the context of the declaration of 'SomeFunction2' the full
definition
of 'std::vector<FooBar>' is not required, it is not going to be
instantiated. If
no instantiation happens, FooBar may be incomplete. The declaration of
'SomFunction2' is legal, I suppose.

Not formally.

C++98 §17.4.3.6/2, about standard library containers:
"In particular, the effects are undefined in the following cases:
[blah blah]
- if an incomplete type (3.9) is used as a template argument when
instantiating a template component"
Why do you think the declaration in OP has to instantiate std::vector<FooBar>?

From 14.7.1-1 (C++ 2003):
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.

std::vector<FooBar>& does not seem to require a completely-defined object.

-Pavel
 
A

Alf P. Steinbach /Usenet

* Pavel, on 09.04.2011 05:17:
Alf said:
* Victor Bazarov, on 08.04.2011 23:41:
On 4/8/2011 5:31 PM, Stephen Howe wrote:
Hi

I cant find whether this is valid C++, but I believe it is

// ---------------------------- start header file
#include<vector>

// Forward Declaration
class FooBar;

int SomeFunction1(FooBar); // Valid
declaration, I know this
int SomeFunction2(std::vector<FooBar>& ref); // But is this, on
using std::vector???

// ---------------------------- end header file

Yes FooBar is incomplete but all I am interested in is whether it is a
valid declaration.
All of this is to minimise header file dependency, so FooBar's
definition is not dragged in.
I know that where SomeFunction2 is defined, a full definition of
FooBar is needed.

Since in the context of the declaration of 'SomeFunction2' the full
definition
of 'std::vector<FooBar>' is not required, it is not going to be
instantiated. If
no instantiation happens, FooBar may be incomplete. The declaration of
'SomFunction2' is legal, I suppose.

Not formally.

C++98 §17.4.3.6/2, about standard library containers:
"In particular, the effects are undefined in the following cases:
[blah blah]
- if an incomplete type (3.9) is used as a template argument when
instantiating a template component"

That is, standard libary containers are special, in that the element
type must (formally) be complete.

A compiler is free to check, by any means, that the type is complete.

Doing such checking yourself might look like this:


<code>
namespace pedantic {

template< class Elem, int enforcedCompleteness = sizeof( Elem ) >
class Vector
{
// ...
};
}

// Forward Declaration
class FooBar;

int SomeFunction1( FooBar ); // Valid.
int SomeFunction2( pedantic::Vector<FooBar>& ref ); // Invalid.

int main()
{}
</code>
Why do you think the declaration in OP has to instantiate std::vector<FooBar>?

From 14.7.1-1 (C++ 2003):
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.

std::vector<FooBar>& does not seem to require a completely-defined object.

Uh, you're right, it's not instantiated here. Sorry for noize.


Cheers & hth.,

- Alf
 
S

Stephen Howe

     C++98 17.4.3.6/2, about standard library containers:
     "In particular, the effects are undefined in the following cases:
      [blah blah]
      - if an incomplete type (3.9) is used as a template argument when
        instantiating a template component"

Yes but Alf I am only interested in legality of declaration, not
definition (nor instantiation).
I can assure you that at the point when I call the function, the full
definition of FooBar will be available.

I am trying to minimise the amount of header file inclusion by forward
declaring items as much as possible.
I know that it perfectly legal for non-template class/struct/union
parameters (but interestingly enum is left out (any aficionado saying
that size matters here is wrong, if it does not matter for class/
struct/union, it should not matter for enum; enum has been
overlooked)).
I was just discussing the legality of template container parameters
where the containing type is incomplete, and as others have concluded,
it is legal.

That just leaves std::string and similar where unfortunately you do
have to do have to do #include <string>, you cannot forward declare.
And I do know about header file <iosfwd> which is useful to know (wish
other std::eek:bject types had a fwd header).

Thanks

Stephen Howe
 
S

Stephen Howe

Pavel

If I had

int SomeFunction3(std::vector<FooBar> ref);

in a declaration, I dont think this requires FooBar to be complete
either.

For a long time, I thought only references and pointer types can be
incomplete.
But I read Scott Meyers and he assured return-by-value and pass-by-
value types can also be incomplete (as long as it just a declaration).
This seems right.
I went through another round of removing headers and replacing with
forward declarations.

I think the template containers with incomplete types have exactly the
same semantics as struct/class/union parameters that are incomplete.

This is great news - miminise header file dependency, increase
compilation speed (less headers for the compiler to wade through). If
I do "#include myheader.h", I really want to minimise the number of
dependent headers that are sub-included.

All that really matters is when you come to call the function or
define it, you do have full set of definitions then.

Thanks

Stephen Howe
 
P

Pavel

Stephen said:
Pavel

If I had

int SomeFunction3(std::vector<FooBar> ref);

in a declaration, I dont think this requires FooBar to be complete
either.

For a long time, I thought only references and pointer types can be
incomplete.
But I read Scott Meyers and he assured return-by-value and pass-by-
value types can also be incomplete (as long as it just a declaration).
This seems right.
I went through another round of removing headers and replacing with
forward declarations.

I think the template containers with incomplete types have exactly the
same semantics as struct/class/union parameters that are incomplete.

This is great news - miminise header file dependency, increase
compilation speed (less headers for the compiler to wade through). If
I do "#include myheader.h", I really want to minimise the number of
dependent headers that are sub-included.

All that really matters is when you come to call the function or
define it, you do have full set of definitions then.

Thanks

Stephen Howe
Thanks Stephen!

This is a nice feature to slash some compilation time, especially for headers
with fat APIs where complete types of many parameters are not needed till the
end of the including translation unit. It's somewhat less of a saver for highly
coherent APIs.

-Pavel
 

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,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top