473,503 Members | 1,300 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Forward declarations aren't allowed any more?

Hi all,

I've recently upgraded my compiler and some of my code no longer works.
I put it through the Comeau online compiler and it came up with the
same errors, so I'm guessing my code is wrong.

I always thought that if you had a recursive object (where two objects
refer to each other) all you had to do was put in a forward declaration
so the compiler knew what was going on. Now it seems this no longer
works. Could anyone please enlighten me as to the correct way I should
be doing this?

The code below demonstrates the problem - it won't compile.

Many thanks,
Adam.

---

struct B;

struct A
{
B getB(void)
{
return B();
}
};

struct B
{
A getA(void)
{
return A();
}
};

int main(void)
{
A a;
B b;

A ba = b.getA();
B ab = a.getB();

return 0;
}
Jul 29 '08 #1
8 1106
Move the definition of A::getB to somewhere after struct B.
>
I bet that's what your compiler is telling you also.
It was, but I'm still not clear how to do that. My example was perhaps
a bit simplistic (I see what you mean with my example code) but my real
code uses templates, so it's not quite as easy to move the definitions
around (see below.)

I'm a bit reluctant to start throwing "extern" and "export" keywords
around, as it seems that compiler support may not be that great yet
(http://www.parashift.com/c++-faq-lit...html#faq-35.12)

The code below gives the same error, and if I move the definitions out
into their own .cpp files as is I get linker errors.

Is there a standard (and well supported) way to avoid the linker errors?

Thanks again,
Adam.

--- test.cpp ---

#include "a.hpp"
#include "b.hpp"

int main(void)
{
A a;
B b;

A ba = b.getA<A>();
B ab = a.getB<B>();

return 0;
}

--- a.hpp ---

#ifndef __A_HPP__
#define __A_HPP__

struct A;

#include "b.hpp"

struct A
{
template <class T>
B getB(void)
{
return B();
}
};

#endif

--- b.hpp ---

#ifndef __B_HPP__
#define __B_HPP__

struct B;

#include "a.hpp"

struct B
{
template <class T>
A getA(void)
{
return A();
}
};

#endif

---
Jul 29 '08 #2
Is this now your "real" code, or is your "real" code something third again?
>
I don't think anyone in this group is real happy chasing phantoms when
trying to help someone.

If you want help then post real code, not made-up examples that you
think resemble real code.
I'm sorry about that, I do realise how annoying it is to offer solutions
and then discover the wrong question was asked, but it was an attempt to
offer clear, easy to read code to make it quicker for everyone to
comprehend - I'm sure everyone here is very busy, so I try to save them
time by making my example code concise.

In this case I accidentally over-simplified, so I apologise for that. I
am not an expert, after all.

This is of course not my "real" code, as the particular code in question
is over 600 lines and won't compile unless there are another dozen or so
files of similar length - I'm sure nobody here has the desire to read
through that!

The latest example code I posted is, to the best of my knowledge, an
accurate representation of the problem. A function template in two
non-template classes access each other's class. The only difference in
my "real" code is that the reference is in the form of a function call
on a parameter, rather than a return value, however as far as I'm aware
that doesn't make a difference in this particular case.
>struct A;

#include "b.hpp"

This is extremely bad. "b.hpp" should be self-contained. It should not
require client code to make any forward declarations before the #include.
"b.hpp" *is* self contained. You will notice that it pulls in a.hpp (to
declare struct A) if required, double-underscore macros aside. Client
code can include just one of either a.hpp or b.hpp (or both) and it will
work as expected. These two files are part of the same "library" if you
will, so I believe their interdependence is acceptable, especially
considering the client code does not need to treat them any differently.

If you have any suggestions for a better way of implementing this while
keeping the declaration of A and B separate, I'd be very keen to know!

Cheers,
Adam.
Jul 29 '08 #3
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Adam Nielsen wrote:
I always thought that if you had a recursive object (where two objects
refer to each other) all you had to do was put in a forward declaration
so the compiler knew what was going on. Now it seems this no longer
works. Could anyone please enlighten me as to the correct way I should
be doing this?

The code below demonstrates the problem - it won't compile.

Many thanks,
Adam.

---

struct B;

struct A
{
B getB(void)
{
return B();
^^^
There's your problem: you are telling the compiler to build a B without
having told it how to do it yet.

Try this (compiles with g++ 4.1.2):

- ---

struct B;

struct A
{
B getB();
};

struct B
{
A getA(void)
{
// no problem, the compiler already knows how to build an A
return A();
}
};

// Ok, now the compiler knows how to build a B
B A::getB()
{
return B();
}

int main(void)
{
A a;
B b;

A ba = b.getA();
B ab = a.getB();

return 0;
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (GNU/Linux)
Comment: Using GnuPG with SUSE - http://enigmail.mozdev.org

iD8DBQFIjsfPBIpu+y7DlLcRAtDTAJ4tcGoNY1/v6202A9ebkZRta65XygCffoO8
hLXrtSwrdhAg4KSV9pitk8Y=
=XlYN
-----END PGP SIGNATURE-----
Jul 29 '08 #4
Hi Federico,
> return B();
^^^
There's your problem: you are telling the compiler to build a B without
having told it how to do it yet.
Yes, you're right - thanks for your reply. I'm used to dealing with
pointers (trying to switch to references) so I had forgotten about that.
Try this (compiles with g++ 4.1.2):
Yes, that works for me too. Unfortunately I neglected to mention that
the functions are actually template functions, so although your solution
still works with template functions, I'm unsure how to take it a step
further and separate the implementation of the template functions off
into a separate file - I keep getting linker errors.

I'm aware of a few potential workarounds, but they seem to be
compiler-specific (or not implemented.)

Cheers,
Adam.
Jul 29 '08 #5
Adam Nielsen wrote:
Hi Federico,
>> return B();
^^^
There's your problem: you are telling the compiler to build a B
without having told it how to do it yet.

Yes, you're right - thanks for your reply. I'm used to dealing with
pointers (trying to switch to references) so I had forgotten about
that.
>Try this (compiles with g++ 4.1.2):

Yes, that works for me too. Unfortunately I neglected to mention
that the functions are actually template functions, so although
your solution still works with template functions, I'm unsure how
to take it a step further and separate the implementation of the
template functions off into a separate file - I keep getting linker
errors.
You can still use Federico's solution for templates, but you might
have to keep it all in the same file.

The basic idea is to have the "return B()" in a place where the
compiler actually knows what a B is (not just that it is some class).
Bo Persson

Jul 29 '08 #6
On Jul 29, 11:21 am, "Bo Persson" <b...@gmb.dkwrote:
Adam Nielsen wrote:
Hi Federico,
> return B();
^^^
There's your problem: you are telling the compiler to build a B
without having told it how to do it yet.
Yes, you're right - thanks for your reply. I'm used to
dealing with pointers (trying to switch to references) so I
had forgotten about that.
Try this (compiles with g++ 4.1.2):
Yes, that works for me too. Unfortunately I neglected to
mention that the functions are actually template functions,
so although your solution still works with template
functions, I'm unsure how to take it a step further and
separate the implementation of the template functions off
into a separate file - I keep getting linker errors.
You can still use Federico's solution for templates, but you might
have to keep it all in the same file.
The basic idea is to have the "return B()" in a place where
the compiler actually knows what a B is (not just that it is
some class).
There is one trick that might be usable. (Note that I've never
actually tried this, so buyer beware.) Make the actual function
a template, e.g.:

template< typename T >
class A
{
public:
template< typename U >
U get() { return U() ; }
} ;

Of course, the client code will then have to write a.get<B>(),
rather than a.getB(). (And of course, B will have to be fully
defined before the client code calls A::get<B>().)

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 29 '08 #7
In message <vb******************************@posted.comnet> , Alf P.
Steinbach <al***@start.nowrites
>* Adam Nielsen:
[..]
>}
--- a.hpp ---
#ifndef __A_HPP__

Symbols with double underscore are reserved for the implementation.
I wouldn't be surprised if that symbol was automatically generated _by_
the implementation, or at least the associated IDE. In which case...
>You have UB.
.... only when you try to compile under a _different_ implementation.

--
Richard Herring
Jul 30 '08 #8
On Jul 30, 11:01 am, "Alf P. Steinbach" <al...@start.nowrote:
* Richard Herring:
In message <vbadnZTDWv7FIhPVnZ2dnUVZ_qfin...@posted.comnet> , Alf P.
Steinbach <al...@start.nowrites
* Adam Nielsen:
[..]
>}
--- a.hpp ---
#ifndef __A_HPP__
Symbols with double underscore are reserved for the
implementation.
I wouldn't be surprised if that symbol was automatically
generated _by_ the implementation, or at least the
associated IDE. In which case...
You have UB.
... only when you try to compile under a _different_ implementation.
He he, that's a very good argument: always hold the door open
for the possibility that some non-portable code is generated
by the C++ implementation.
Which raises the question: what constitues the "C++
implementation"? I'd tend to exclude code generating Wizards
and such, but who knows. If the Wizard is designed to generate
OWL or OLE or whatever, you can't really require that what it
generates be "portable C++".
Funny I didn't think of that.
I think, though, it must qualify as a red herring. <g>
Now, now. No McCarthyism, please:-). I'm sure you don't really
think that Richard is a communist.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Jul 30 '08 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
5442
by: mjm | last post by:
Folks, Please help me with the following problems: ******************************************** 1. I have a class template template<class Base> class Matrix : public Base { /* .... */ }
11
37038
by: Alexander Grigoriev | last post by:
Not quite new version of GCC that I have to use, craps with the following code: enum E; enum E { e }; That is, it doesn't accept forward declaration of enum. C++ standard text doesn't...
10
2200
by: Alan Lee | last post by:
Hi i am writing a small simulation for a bunch of atoms jumping around on a surface. I know i am a crappy programmer since i am not very familiar with object oriented languages. I am woindering...
6
5188
by: Steven T. Hatton | last post by:
Should I be able to forward declare something from a namespace different from the current one? For example the following code compiles: //testdriver.hpp #ifndef TESTDRIVER_HPP #define...
11
2413
by: aleko | last post by:
This applies equally to function prototypes. Why do we have to tell the compiler twice? Other modern compiled languages don't have this requirement. Just curious, Aleko
134
7747
by: James A. Donald | last post by:
I am contemplating getting into Python, which is used by engineers I admire - google and Bram Cohen, but was horrified to read "no variable or argument declarations are necessary." Surely that...
23
3817
by: mark.moore | last post by:
I know this has been asked before, but I just can't find the answer in the sea of hits... How do you forward declare a class that is *not* paramaterized, but is based on a template class? ...
8
2016
by: Simon Brooke | last post by:
I was debugging a new XML generator tonight and trying to determine why it wasn't working; and realised my dom printer does not output XML namespace declarations. My method to output an Element...
11
8292
by: Jef Driesen | last post by:
I have the following problem in a C project (but that also needs to compile with a C++ compiler). I'm using a virtual function table, that looks like this in the header file: typedef struct...
0
7089
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
1
6995
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
7463
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
5581
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
5017
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
4678
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
3157
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
1515
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
1
738
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.