Template file extension / inclusion / declaration

N

Nomak

Hello all,

i have two template classes which needs each other. I tried to write
some fwd decl / decl / impl in a good way but i can't get it to
compile.

Explanations:
- .hh files are for declaration (template or not)
- .hxx files are template impl

I would like to avoid some .ixx file for forward declaration. I'm
searching for a clever way.

Here are the files:

====> a.hh <====
1 /*
2 * A decl
3 */
4 #ifndef A_HH
5 #define A_HH
6
7 // fwd decl
8 class ostream;
9 class B;
10
11
12 template <typename T>
13 class A
14 {
15 public:
16 A(const T & t);
17 A(const B<T> & b);
18
19 void dump(ostream & os) const;
20 };
21
22 #endif // ! A_HH
23

====> a.hxx <====
1 /*
2 * A impl
3 */
4 #ifndef A_HXX
5 #define A_HXX
6
7 // need self decl
8 #include "a.hh"
9
10 // need impl
11 #include <ostream>
12 #include "b.hxx"
13
14 template <typename T>
15 A<T>::A(const T & t)
16 {
17 }
18
19 template <typename T>
20 A<T>::A(const B<T> & b)
21 {
22 }
23
24 template <typename T>
25 A<T>::dump(ostream & os)
26 {
27 os << "dump";
28 }
29
30 #endif // ! A_HXX

====> b.hh <====
1 /*
2 * B decl
3 */
4 #ifndef B_HH
5 #define B_HH
6
7 // fwd decl
8 using std::eek:stream;
9 using A;
10
11
12 template <typename T>
13 class B
14 {
15 public:
16 B(const T & t);
17 B(const A<T> & b);
18
19 void dump(ostream & os) const;
20 };
21
22 #endif // ! B_HH

====> b.hxx <====
1 /*
2 * B impl
3 */
4 #ifndef B_HXX
5 #define B_HXX
6
7 // need self decl
8 #include "b.hh"
9
10 // need impl
11 #include <ostream>
12 #include "a.hxx"
13
14 template <typename T>
15 B<T>::B(const T & t)
16 {
17 }
18
19 template <typename T>
20 B<T>::B(const A & b)
21 {
22 }
23
24 template <typename T>
25 B<T>::dump(ostream & os)
26 {
27 os << "dump";
28 }
29
30 #endif // ! B_HXX

====> main.cc <====
1 /*
2 * Program
3 */
4
5 // need impl
6 #include "a.hxx"
7 #include "b.hxx"
8
9
10 int
11 main()
12 {
13 {
14 A<int> a1(1);
15
16 B<int> b1(2);
17 B<int> b2(a1);
18
19 A<int> a2(b1);
20 }
21 return 0;
22 }
23


$ g++-3.4.0 -Wall main.cc
In file included from a.hxx:8,
from main.cc:6:
a.hh:17: error: `B' is not a template
In file included from b.hxx:8,
from a.hxx:12,
from main.cc:6:
b.hh:8: error: `ostream' is already declared in this scope
b.hh:9: error: expected nested-name-specifier before "A"
b.hh:9: confused by earlier errors, bailing out


Is there a standard way to handle that?

TIA

NB: i've read several times "inline" to indicate that template
implementation must be included in the same compilation unit (included
from the same .cc) as the declaration. I thought inline was in fact
"implicit inlining" which is having the decl and impl mixed (in the
class decl). Who's right?
 
R

Rob Williscroft

Nomak wrote in in
comp.lang.c++:
Hello all,

i have two template classes which needs each other. I tried to write
some fwd decl / decl / impl in a good way but i can't get it to
compile.

Explanations:
- .hh files are for declaration (template or not)
- .hxx files are template impl

I would like to avoid some .ixx file for forward declaration. I'm
searching for a clever way.

Here are the files:

====> a.hh <====
1 /*
2 * A decl
3 */
4 #ifndef A_HH
5 #define A_HH
6
7 // fwd decl

#inclue said:
8 class ostream;

template said:
9 class B;
10
11
12 template <typename T>
13 class A
14 {
15 public:
16 A(const T & t);
17 A(const B<T> & b);
18

void dump( std::eek:stream & os) const;

19 void dump(ostream & os) const;
20 };
21
22 #endif // ! A_HH
23

====> a.hxx <====
1 /*
2 * A impl
3 */
[snip]

23
24 template <typename T>

25 A<T>::dump(ostream & os)
26 {
====> b.hh <====
1 /*

Not in a header file
8 using std::eek:stream;

What is this supposed to do (i.e loose it)
9 using A;

std::

19 void dump(ostream & os) const;
std::


24 template <typename T>
25 B<T>::dump(ostream & os)
26 {
[snip]


NB: i've read several times "inline" to indicate that template
implementation must be included in the same compilation unit (included
from the same .cc) as the declaration. I thought inline was in fact
"implicit inlining" which is having the decl and impl mixed (in the
class decl). Who's right?

Sorry, but I can't make any sense of that paragraph.

In the absence of /export/ the compiler needs to see defenition's for
all templates that haven't been instantiated in another translation unit.
Otherwise it can't instantiate them and you get a "unresolved symbol"
linker error.

HTH.

Rob.
 
N

Nomak

Le 15/06/2004 à 06:28:08 said:

Sorry, but I can't make any sense of that paragraph.

In the absence of /export/ the compiler needs to see defenition's for
all templates that haven't been instantiated in another translation unit.
Otherwise it can't instantiate them and you get a "unresolved symbol"
linker error.

Ok let's try again :
- i've read several times "inline" to indicate that template
implementation must be included in the same *translation* unit
(included from the same .cc) as the declaration:

a.hh:

class A { ... };

#include "a.hxx" // inline

- I thought inline was in fact "implicit inlining" which is having the
decl and impl mixed (in the class decl):

a.hh

class A
{
public:
A() { /* implicit "inline" keyword ~= macro like */ };
....
};

What is correct use of "inline"?

And here is the working code, with several drawbacks:

===> a.hh <====
/*
* A decl
*/
#ifndef A_HH
#define A_HH

// fwd decl
#include <iosfwd> // ok for ostream, but ...
template <class _T1, class _T2> struct pair; // ... for std::pair ?
template <typename T> class B; // by-hand copy => sucks


template <typename T>
class A
{
public:
typedef pair< T, int > pair_type;

A(const T & t);
A(const B<T> & b);

void use_pair(pair_type p);
void dump(std::eek:stream & os) const;
};

#endif // ! A_HH


===> a.hxx <====
/*
* A impl
*/
#ifndef A_HXX
#define A_HXX

// need self decl
#include "a.hh"

// need impl
#include <ostream>
#include "b.hxx"

// don't want to have std:: everywhere
using std::eek:stream;

template <typename T>
A<T>::A(const T & t)
{
}

template <typename T>
A<T>::A(const B<T> & b)
{
}

template <typename T>
void
A<T>::use_pair(pair_type p)
{
}

template <typename T>
void
A<T>::dump(ostream & os) const
{
os << "dump";
}

#endif // ! A_HXX

===> b.hh <====
/*
* B decl
*/
#ifndef B_HH
#define B_HH

// fwd decl
#include <iosfwd>
template <typename T> class A;


template <typename T>
class B
{
public:
B(const T & t);
B(const A<T> & b);

void dump(std::eek:stream & os) const;
};

#endif // ! B_HH

===> b.hxx <====
/*
* B impl
*/
#ifndef B_HXX
#define B_HXX

// need self decl
#include "b.hh"

// need impl
#include <ostream>
#include "a.hxx"

// don't want std::*
using std::eek:stream;

template <typename T>
B<T>::B(const T & t)
{
}

template <typename T>
B<T>::B(const A<T> & b)
{
}

template <typename T>
void
B<T>::dump(ostream & os) const
{
os << "dump";
}

#endif // ! B_HXX

===> main.cc <====
/*
* Program
*/

// need impl
#include "a.hxx"
#include "b.hxx"


int
main()
{
{
A<int> a1(1);

B<int> b1(2);
B<int> b2(a1);

A<int> a2(b1);
}
return 0;
}


Compilation of this is fine.

But your solution is in fact having to write the forward decls by hand
each time. Almost the same as creating .ixx for personnal template,
and for STL template wich don't have a forward header, writing the fwd
decls by hand is really bad (default args, hard to keep update).

For std::pair i had to get the fwd decl for /usr/include.../stl_pair.h
....
 
R

Rob Williscroft

Nomak wrote in in
comp.lang.c++:
Le 15/06/2004 à 06:28:08 said:

Sorry, but I can't make any sense of that paragraph.

In the absence of /export/ the compiler needs to see defenition's for
all templates that haven't been instantiated in another translation
unit. Otherwise it can't instantiate them and you get a "unresolved
symbol" linker error.

Ok let's try again :
- i've read several times "inline" to indicate that template
implementation must be included in the same *translation* unit
(included from the same .cc) as the declaration:

a.hh:

class A { ... };

#include "a.hxx" // inline

- I thought inline was in fact "implicit inlining" which is having the
decl and impl mixed (in the class decl):

No templates *don't* require inline-ing (implicit or otherwise).

But (in absence of *export*) the defenition's do have to be
made available to the compiler:

// A declaration:
template < typename T > void f( T const & );

// A Defenition:

template < typename T > void f( T const & )
{
}
a.hh

class A
{
public:
A() { /* implicit "inline" keyword ~= macro like */ };
...
};

What is correct use of "inline"?

inline is for inlining it has *nothing* to do with templates.
And here is the working code, with several drawbacks:

===> a.hh <====
/*
* A decl
*/
#ifndef A_HH
#define A_HH

// fwd decl
#include <iosfwd> // ok for ostream, but ...
template <class _T1, class _T2> struct pair; // ... for std::pair ?

Sorry your out of luck here, the C++ Standard forbids *us* (ordinary
users / non-implementers) from making declaration's in namespace std.

Not that the above is (I assume you have an old / broken compiler).

#include said:
template <typename T> class B; // by-hand copy => sucks

Yes, but that is how C++ works, we're stuck with it.
template <typename T>
class A
{
public:
typedef pair< T, int > pair_type;

Missing std:: again (BTW don't use "using namespace" in a header
file) it causes your code to "suck" to borrow your technical term.
A(const T & t);
A(const B<T> & b);

void use_pair(pair_type p);
void dump(std::eek:stream & os) const;
};

#endif // ! A_HH


===> a.hxx <====
/*
* A impl
*/
#ifndef A_HXX
#define A_HXX

// need self decl
#include "a.hh"

// need impl
#include <ostream>
#include "b.hxx"
// don't want to have std:: everywhere
using std::eek:stream;

Well it isn't as bad as "using namespace" but it still
bad, though its worse for non-std names.

[major snip]
Compilation of this is fine.

But your solution is in fact having to write the forward decls by hand
each time. Almost the same as creating .ixx for personnal template,
and for STL template wich don't have a forward header, writing the fwd
decls by hand is really bad (default args, hard to keep update).

Yes its a *known* problem (*), and if you do it yourself your programme
exhibts UB (Undefined Behaviour) IOW all bets are off, The C++ Standard
nolonger cares what you programme does.

but they never seem to said:
For std::pair i had to get the fwd decl for /usr/include.../stl_pair.h
...

Yup and still you got it wrong:

namespace std
{
template < typename F, typename S > struct pair;
}

#include <utility> /* it works, look ma no UB! :) */

Rob.
 
N

Nomak

Le 15/06/2004 à 11:43:20 said:
No templates *don't* require inline-ing (implicit or otherwise).

My question was what are the definitions of "inline". I've seen 2
definitions at least.
But (in absence of *export*) the defenition's do have to be
made available to the compiler:
in the same translation unit.
Because the linker cannot help us for template without the export
keyword.
// A declaration:
template < typename T > void f( T const & );

// A Defenition:

template < typename T > void f( T const & )
{
}

I know that.

inline is for inlining it has *nothing* to do with templates.

Hum... several tutorial are wrong if so.

Sorry your out of luck here, the C++ Standard forbids *us* (ordinary
users / non-implementers) from making declaration's in namespace std.

Good to know

Not that the above is (I assume you have an old / broken compiler).

g++-3.4.0 ??
#include <utility> /* its not *that* big :) */

Well i was hopping for a general way. So ios* have a fwd header but
not the rest of the STL...

Yes, but that is how C++ works, we're stuck with it.
:(



Missing std:: again (BTW don't use "using namespace" in a header
file) it causes your code to "suck" to borrow your technical term.
;)




Well it isn't as bad as "using namespace" but it still
bad, though its worse for non-std names.

I don't think so. Tools to remove ambiguities must be use only when
there are some ambiguities to remove.

[major snip]
Compilation of this is fine.

But your solution is in fact having to write the forward decls by hand
each time. Almost the same as creating .ixx for personnal template,
and for STL template wich don't have a forward header, writing the fwd
decls by hand is really bad (default args, hard to keep update).

Yes its a *known* problem (*), and if you do it yourself your programme
exhibts UB (Undefined Behaviour) IOW all bets are off, The C++ Standard
nolonger cares what you programme does.

*) People keep proposing solutions <stdfwd>, but they never seem to
get anywhere :(.

damned ! ;) big headers in my code !!!

Yup and still you got it wrong:

namespace std
{
template < typename F, typename S > struct pair;
}

#include <utility> /* it works, look ma no UB! :) */

even worse to keep updated. And still UB. What a langage ;)
 
R

Rob Williscroft

Nomak wrote in in
comp.lang.c++:
My question was what are the definitions of "inline". I've seen 2
definitions at least.

inline
------

A function specifier that used with a function defenition
*requests* that the compiler "inlines" the defined code.
i.e. instead of making one copy of the code and calling that
every time it is called, the code is inserted at the call site.

implicit-inline
---------------

Is just that the inline keyword is assumed for member function
defenitions given inside a class defenition.

The full defenition in the standard (7.1.2) is a bit more complex
than the above, but not much.

The C++ Standard is available here: http://tinyurl.com/2dw75
You can also get a PDF version which is even cheaper.
http://www.techstreet.com/cgi-bin/detail?product_id=1143945
in the same translation unit.

Yes, but that doesn't mean header file, you can still put your
declaration's in one header and your defenitions in another,
should you wish to.
Because the linker cannot help us for template without the export
keyword.

[snip]
inline is for inlining it has *nothing* to do with templates.

Hum... several tutorial are wrong if so.

Yes there are plenty of bad tutorials and bad books out there.

Rob.
 

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,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top