473,659 Members | 2,659 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 1111
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

iD8DBQFIjsfPBIp u+y7DlLcRAtDTAJ 4tcGoNY1/v6202A9ebkZRta6 5XygCffoO8
hLXrtSwrdhAg4KS V9pitk8Y=
=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.dkwro te:
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 objektorientier ter Datenverarbeitu ng
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.comn et>, Alf P.
Steinbach <al***@start.no writes
>* 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.no wrote:
* Richard Herring:
In message <vbadnZTDWv7FIh PVnZ2dnUVZ_qfin ...@posted.comn et>, Alf P.
Steinbach <al...@start.no writes
* 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 objektorientier ter Datenverarbeitu ng
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
5462
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
37069
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 explicitly say about enum's forward declaration, but one example shows it in 18.2.1, clause 4:
10
2222
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 if anyone can tell me why my forward class declarations not working. the member function findpaths can't seem to access the class Board when I try to pass it a board object by value. I put the Board class latrerbut also put in a forward...
6
5199
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 TESTDRIVER_HPP #include <ostream> namespace ns_testdriver{ using std::ostream;
11
2427
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
7859
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 means that if I misspell a variable name, my program will mysteriously fail to work with no error message. If you don't declare variables, you can inadvertently re-use an variable used in an enclosing context when you don't intend to, or
23
3841
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? Here's what I thought should work, but apparently doesn't: class Foo; void f1(Foo* p)
8
2029
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 is as follows: /** * Print an element node, and, by recursive descent, it's children * * @param node the node to print
11
8310
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 device_t { const device_backend_t *backend; ... } device_t; typedef struct device_backend_t {
0
8427
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8332
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 effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
1
8525
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 Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
8627
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 protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
7356
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, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
0
5649
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 then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4175
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
1975
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
2
1737
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.