0

I have two classes whose functions take typedefed pointers to eachother as return values and parameters. I.e.:

class Segment;

class Location : public Fwk::NamedInterface {
  public:
    // ===== Class Typedefs =====
    typedef Fwk::Ptr<Location const> PtrConst;
    typedef Fwk::Ptr<Location> Ptr;
    // ===== Class Typedefs End =====
    void segmentIs(Segment::Ptr seg);
    /* ... */
}

and class Location;

class Segment : public Fwk::NamedInterface {
  public:
    // ===== Class Typedefs =====
    typedef Fwk::Ptr<Segment const> PtrConst;
    typedef Fwk::Ptr<Segment> Ptr;
    // ===== Class Typedefs End =====
    void locationIs(Location::Ptr seg);
    /* ... */
 }

This understandably generated linker errors...which the forward declarations of the respective classes don't fix. How can I forward declare the Ptr and PtrConst typedefs while keeping these typedefs internal to the class (i.e. I would like to write Location::Ptr to refer to the location pointer type)?

Thanks folks!

bcr
  • 1,328
  • 11
  • 27

2 Answers2

1

There's a hidden metafunction in there which takes a type T and returns Fwk::Ptr< T >. You have implemented this metafunction twice. Implementing it inside the classes introduces a false dependency of the metafunction upon the classes.

To remove this false dependency, implement the metafunction before anything else.

template< typename T >
using FwkPtr = Fwk::Ptr< T >;

(Edit: here is a C++03 style metafuction.

template< typename T >
struct FwkPtr {
    typedef Fwk::Ptr< T > type;
};

Then you would refer to FwkPtr< Segment >::type, or if the metafunction is applied to a template parameter or result thereof, typename FwkPtr< T >::type.)

If in the future Segment and Location are templated so their Ptr members could be something else, then the problem goes away because of delayed evaluation. But the fix still works, and it's still conceptually valid.

You might (ultimately) have the metafunction compute something else, or have more than one metafunction. The point is that you don't need the entire class to do it, and it's not a functionality encapsulated by the class.

On the other hand, if the arguments will always certainly be Fwk::Ptr< Segment > and Fwk::Ptr< Location >, you can just specify them that way and sidestep the issue.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • Hey Potatoswatter, thanks for the answer. Where does the implementation of the metafunction go? In each implementing class or at the original Fwk::Ptr declaration? – bcr Nov 06 '13 at 01:58
  • Um… "before anything else," i.e. both `Segment` and `Location`. – Potatoswatter Nov 06 '13 at 01:59
  • It needs to be outside the classes or it wouldn't help. Exactly where it goes depends on exactly what abstraction you're going for. Putting it inside `Fwk` would seem redundant with `Fwk::Ptr` itself. You might be over-architecting it prematurely if there's no clear requirement yet. – Potatoswatter Nov 06 '13 at 02:01
  • Thanks, Potatoswatter! Unfortunately, I'm getting compile errors to the tune of "unqualified-id before `using`"...perhaps I'm not following your suggestion correctly? – bcr Nov 06 '13 at 03:49
  • @bcr The included code requires C++11. I'll update with a C++03 version. – Potatoswatter Nov 06 '13 at 03:50
  • I thought that might be the issue, so I'm compiling with c++0x, I guess that isn't recent enough? – bcr Nov 06 '13 at 03:52
  • @bcr C++0x is a catch-all for pre-standard prototypes of C++11. You might upgrade your compiler, or just use the alternative I just added. – Potatoswatter Nov 06 '13 at 03:53
  • Awesome. Thanks so much! Would have had difficulty working that out on my own. – bcr Nov 06 '13 at 03:54
0

You can't access a type that hasn't been declared

class Location : public Fwk::NamedInterface {
  public:
    // ===== Class Typedefs =====
    typedef Fwk::Ptr<Location const> PtrConst;
    typedef Fwk::Ptr<Location> Ptr;
    // ===== Class Typedefs End =====

    // this is illegal
    void segmentIs(Segment::Ptr seg);
};

Instead, try typedef'ing outside the class.

class Segment;
class Location;
typedef Fwk::Ptr<Segment>  SegmentPtr;
typedef Fwk::Ptr<Location> LocationPtr;

class Location : public Fwk::NamedInterface {
  public:
    // ===== Class Typedefs =====
    typedef Fwk::Ptr<Location const> PtrConst;
    // ===== Class Typedefs End =====
    void segmentIs(const SegmentPtr& seg);
};
JRG
  • 2,065
  • 2
  • 14
  • 29
  • unfortunately, this violates my requirement that the :: syntax be used as in Location::Ptr. Is there simply no way to do this? – bcr Nov 06 '13 at 01:44
  • It is impossible. You need to have at least a declaration when the compiler reaches the 'segmentIs' function, and it is illegal to forward declare inner classes; http://stackoverflow.com/a/1021809/464289 – JRG Nov 06 '13 at 01:47