From: Robi-Wan-Kenobi on
Hi all,

the following code isn't compiling:

template<class T>
class containerBase
{

};

class aBase
{

};

class aDerived : public aBase
{

};

void aFunc(containerBase<aBase*>& aContainer)
{

}

void aTestFunc()
{
containerBase<aDerived*> lContainer;
aFunc(lContainer);
}

The compiler (VC 2005) complains containerBase<aDerived*> can't be
converted to containerBase<aBase*>.

But i can't see a reason why.

I could do some brute force casting but i'd prefer some more elegant
way. Is there some common pattern for it?

thanx,
Robert

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

From: Chris Uzdavinis on
On May 19, 11:32 am, Robi-Wan-Kenobi <robert.ka...(a)gmx.de> wrote:
> Hi all,
>
> the following code isn't compiling:
>
> template<class T> class containerBase { };
> class aBase {};
> class aDerived : public aBase {};
>
> void aFunc(containerBase<aBase*>& aContainer){}
>
> void aTestFunc(){
> containerBase<aDerived*> lContainer;
> aFunc(lContainer);
> }
>
> The compiler (VC 2005) complains containerBase<aDerived*> can't be
> converted to containerBase<aBase*>.
>
> But i can't see a reason why.

For any class template C, there is no inheritance relationship between
two instantiations C<T1> and C<T2> regardless of the relationships
between the template parameters themselves.

C<T1> and C<T2> could be as different as night and day, considering the
class could have specializations, etc.

Thus, containerBase<T1*> and containerBase<T2*> are completely unrelated
types, exacpt that they were instantiated from the same template.

Besides, if what you wanted to do were actually allowed, you'd easily be
able to break the type system! Consider:

template<class T> class containerBase { };
class aBase {};
class aDerived : public aBase {};
class aDerived2 : public aBase {};

void aFunc(containerBase<aBase*>& aContainer {
aContainer.insert(new aDerived2);
}

void aTestFunc(){
containerBase<aDerived*> lContainer;
aFunc(lContainer);
}

In this case, it's really a container holding aDerived*, but if you
could convert the container to hold the base type, you'd be able to
insert other types that also derive from aBase, even if they have no
other relationship to aDerived. Thus, your lContainer would have
invalid objects in it.

So it's a good thing the compiler doesn't allow this.


> I could do some brute force casting but i'd prefer some more elegant
> way. Is there some common pattern for it?

Don't cast. Perhaps you could do something like this:

template <typename T>
void aFunc(containerBase<T*>& aContainer {

}

You could even do a static_assert that T inherits from aBase, if you
care about that.

Chris


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

From: Paul Bibbings on
Robi-Wan-Kenobi <robert.kauth(a)gmx.de> writes:

> Hi all,
>
> the following code isn't compiling:
>
> template<class T>
> class containerBase
> {
>
> };
>
> class aBase
> {
>
> };
>
> class aDerived : public aBase
> {
>
> };
>
> void aFunc(containerBase<aBase*>& aContainer)
> {
>
> }
>
> void aTestFunc()
> {
> containerBase<aDerived*> lContainer;
> aFunc(lContainer);
> }
>
> The compiler (VC 2005) complains containerBase<aDerived*> can't be
> converted to containerBase<aBase*>.
>
> But i can't see a reason why.

Parameterized types created from templates are distinct types and, as
such, any inheritance that exists between the arguments used in
instantiating such types - such as is the case between your aBase and
aDerived classes - is *not* transferred to a similar relationship
between those instantiations. Consequently, containerBase<aBase*> and
containerBase<aDerived*> remain unrelated types from the point of view
of inheritance.

> I could do some brute force casting but i'd prefer some more elegant
> way. Is there some common pattern for it?

If you adapt your classes aBase and aDerived so that they actually
exhibit polymorphism, you could at least usefully populate an instance
of containerBase<aBase*> with pointers to either aBase or aDerived
instances, without any need to consider polymorphism of containerBase<>
itself. You may then pass a containerBase<aBase*> - where the stored
pointers point to instances of aDerived as the most derived class - to
aFunc just as in your original attempt. Whether this will get you want
you want from your idea is in the detail, of course.

Regards

Paul Bibbings



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

From: Goran on
On May 19, 6:32 pm, Robi-Wan-Kenobi <robert.ka...(a)gmx.de> wrote:
> Hi all,
>
> the following code isn't compiling:
>
> template<class T>
> class containerBase
> {
>
> };
>
> class aBase
> {
>
> };
>
> class aDerived : public aBase
> {
>
> };
>
> void aFunc(containerBase<aBase*>& aContainer)
> {
>
> }
>
> void aTestFunc()
> {
> containerBase<aDerived*> lContainer;
> aFunc(lContainer);
>
> }
>
> The compiler (VC 2005) complains containerBase<aDerived*> can't be
> converted to containerBase<aBase*>.
>
> But i can't see a reason why.
>
> I could do some brute force casting but i'd prefer some more elegant
> way. Is there some common pattern for it?

+1 for people who explained why it's not good for your code to
compile. That said...
Would this do it for you:

template<class T>
class base_container
{
public:
const T* get() const;
T* get();
void insert(T*);
// etc
};

template<class T, class derivedT>
class base_container_specialized
{
public:
typedef base_container<T> this_base;
private:
this_base _base;
public:
operator const this_base&() { return _base; }

const derivedT* get() const { return static_cast<const
derivedT*>(_base.get()); }
derivedT* get() { return static_cast<derivedT*>(_base.get()); }
void insert(derivedT* p) { _base.insert(p); }
// etc
};

class base{};
class derived1 : public base {};
class derived2 : public base {};

base_container_specialized is NOT_A base_container. It offers same,
but type-safe, interface as base_container. It does so through some
simple casting (from T to derivedT). It also contains base_container,
so that you can get a reference to that if need be (operator const
this_base&). operator is const, to prevent e.g. calling insert with
base* or derived2*, as that would be bad, as others have shown. So
that gives you e.g.

void f0(base_container<base>& c) { c.insert(new base); }
void f0const(const base_container<base>&) {}
void f1(base_container_specialized<base, derived1>&) {}
void f2(base_container_specialized<base, derived2>&) {}

void test()
{
base_container_specialized<base, derived1> c1;
c1.insert(new derived1); //ok
c1.insert(new derived2); //bad
c1.insert(new base); //bad, don't want base among derived1
c1.insert(new derived11);//ok
const base* b = c1.get();//ok, derived1 IS_A base
const derived1* d1 = c1.get();//ok
const derived2* d2 = c1.get();//bad, derived1 !IS_A derived2
f0const(c1);//ok, conversion operator used
f0(c1);//bad, could insert base among derived1
f1(c1);//ok, it's us
f2(c1);//bad, f2 wants derived2 container
}

I would guess that one could also come up with convenient utility to
convert any base_container_specialized<derivedY, derivedZ> where
derivedZ derives from derivedY, to
base_container_specialized<derivedX, derivedY>, where derivedX derives
from derivedY.

Goran.


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

From: Joshua Maurice on
On May 19, 9:32 am, Robi-Wan-Kenobi <robert.ka...(a)gmx.de> wrote:
> Hi all,
>
> the following code isn't compiling:
>
> template<class T>
> class containerBase
> {
>
> };
>
> class aBase
> {
>
> };
>
> class aDerived : public aBase
> {
>
> };
>
> void aFunc(containerBase<aBase*>& aContainer)
> {
>
> }
>
> void aTestFunc()
> {
> containerBase<aDerived*> lContainer;
> aFunc(lContainer);
>
> }
>
> The compiler (VC 2005) complains containerBase<aDerived*> can't be
> converted to containerBase<aBase*>.
>
> But i can't see a reason why.
>
> I could do some brute force casting but i'd prefer some more elegant
> way. Is there some common pattern for it?

This is (partially) answered in the FAQ. See
http://www.parashift.com/c++-faq-lite/proper-inheritance.html


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

 |  Next  |  Last
Pages: 1 2
Prev: restriction on inheritance
Next: information for find