From: Arcadio on
Suppose I have the following:

(in class_a.h):

class Foo;
class ClassA
{
public:
typedef std::vector< boost::shared_ptr<Foo> > Foos;
Foos makeFoos() const;
};


and in another class, I have a method that makes use of a vector of
Foos. Should I do this:

(Try #1, class_b.h):

#include "class_a.h"

class ClassB
{
public:
void useFoos(const ClassA::Foos& foos);
};

or just repeat the typedef in class_b.h like this:

(Try #2, class_b.h):

class Foo;
class ClassB
{
public:
typedef std::vector< boost::shared_ptr<Foo> > Foos;
void useFoos(const Foos& foos);
};


Try #1 seems bad because it creates a dependency between class_a.h and
class_b.h when all I want is the typedef for Foos. Try #2 repeats the
typedef, so it seems like I'm repeating code which also seems bad, but
not as bad as Try #1.

Or should I break out the Foos typedef into it's own header (perhaps
the header file for class Foo?) and have both class_a.h and class_b.h
include that?

Thanks!

-- Arcadio

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Nick Hounsome on
On 19 Feb, 22:37, Arcadio <arcadiosinc...(a)gmail.com> wrote:
> Suppose I have the following:
>
> (in class_a.h):
>
> class Foo;
> class ClassA
> {
> public:
> typedef std::vector< boost::shared_ptr<Foo> > Foos;
> Foos makeFoos() const;
>
> };
>
> and in another class, I have a method that makes use of a vector of
> Foos. Should I do this:
>
> (Try #1, class_b.h):
>
> #include "class_a.h"
>
> class ClassB
> {
> public:
> void useFoos(const ClassA::Foos& foos);
>
> };
>
> or just repeat the typedef in class_b.h like this:
>
> (Try #2, class_b.h):
>
> class Foo;
> class ClassB
> {
> public:
> typedef std::vector< boost::shared_ptr<Foo> > Foos;
> void useFoos(const Foos& foos);
>
> };
>
> Try #1 seems bad because it creates a dependency between class_a.h and
> class_b.h

Agreed.
Unless B actually uses A it is probably not right to include it just
to get a typedef.

> when all I want is the typedef for Foos. Try #2 repeats the
> typedef, so it seems like I'm repeating code which also seems bad, but
> not as bad as Try #1.

ClassA::Foos is LOGICALLY a different type to ClassB::Foos so UNLESS
they are logically coupled in some other way.
so you are not logically repeating anything even though they actually
happen to have the same type.

>
> Or should I break out the Foos typedef into it's own header (perhaps
> the header file for class Foo?) and have both class_a.h and class_b.h
> include that?

That is possible but undesirable for a typedef - At the very least you
would want to put it in a namespace.

In some circumstances it can make sense to put the typedef in either
Foo itself or in some sort of traits class:
CollectionTraits<Foo>::CollectionType...
but probably not here.

The "cleanest" solution to the problem of passing a collection from
one type to another is to pass it to a template method as either a
standard collection or a pair of standard iterators. The only problem
with this is that it often exposes more than you would wish in the
header.

class ClassB
{
template <class FooCollection>
void useFoos(const FooCollection& foos) {...}

template <class Iter>
void useFoos(Iter begin,Iter end) {...}
}

This allows you to change ClassA::makeFoos (to std::list say) without
breaking any code.


--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]