By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,805 Members | 1,056 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,805 IT Pros & Developers. It's quick & easy.

Template file extension / inclusion / declaration

P: n/a
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::ostream;
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?

--
Nomak
Jul 22 '05 #1
Share this Question
Share on Google+
5 Replies


P: n/a
Nomak wrote in news:1v*******************************@40tude.net 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 <iosfwd>
8 class ostream;
template < typename T > class B;
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::ostream & 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>
A<T>::dump( std::ostream & os)

25 A<T>::dump(ostream & os)
26 {
====> b.hh <====
1 /*
Not in a header file
8 using std::ostream;
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.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #2

P: n/a
Le 15/06/2004 à 06:28:08, Rob Williscroft <rt*@freenet.co.uk> a écrit:
[...]


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::ostream & 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::ostream;

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::ostream & 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::ostream;

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
....

--
Nomak
Jul 22 '05 #3

P: n/a
Nomak wrote in news:1b*******************************@40tude.net in
comp.lang.c++:
Le 15/06/2004 à 06:28:08, Rob Williscroft <rt*@freenet.co.uk> a écrit:
[...]
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 <utility> /* its not *that* big :) */
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::ostream & 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::ostream;
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.

*) People keep proposing solutions <stdfwd>, but they never seem to
get anywhere :(.
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.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #4

P: n/a
Le 15/06/2004 à 11:43:20, Rob Williscroft <rt*@freenet.co.uk> a écrit:
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).


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.

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.


Hum... several tutorial are wrong if so.

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.


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...

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::ostream & 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::ostream;


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 !!!

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! :) */


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

--
Nomak
Jul 22 '05 #5

P: n/a
Nomak wrote in news:k6*****************************@40tude.net in
comp.lang.c++:
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.


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/de...uct_id=1143945
But (in absence of *export*) the defenition's do have to be
made available to the compiler: 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]

What is correct use of "inline"?


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.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #6

This discussion thread is closed

Replies have been disabled for this discussion.