From: fabio.lombardelli on
Hi all,
can somebody explain me why this piece of code doesn't compile?
In particular, why the compiler (on Base<Derived> class) can see _fun,
and why it can't see _DType?

template <typename D>
struct Base
{
typedef typename D::_DType DType;

void fun()
{
static_cast<D*>(this)->_fun();
}
};

struct Derived : public Base<Derived>
{
typedef int _DType;

void _fun() {}
};

Maybe Base<Derived> class knows Derived class just as a forward
declaration.
But if it is so, why it can see the method _fun?

Thanks in advance.
--
Fabio


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

From: red floyd on
fabio.lombardelli(a)gmail.com wrote:
> Hi all,
> can somebody explain me why this piece of code doesn't compile?
> In particular, why the compiler (on Base<Derived> class) can see _fun,
> and why it can't see _DType?
>
> template <typename D>
> struct Base
> {
> typedef typename D::_DType DType;
>
> void fun()
> {
> static_cast<D*>(this)->_fun();
> }
> };
>
> struct Derived : public Base<Derived>
> {
> typedef int _DType;
>
> void _fun() {}
> };
>
> Maybe Base<Derived> class knows Derived class just as a forward
> declaration.
> But if it is so, why it can see the method _fun?
>

FWIW, Comeau online complains about an incomplete type at the point of
instantiation.

"ComeauTest.c", line 4: error: incomplete type is not allowed
typedef typename D::_DType DType;
^
detected during instantiation of class "Base<D> [with
D=Derived]" at
line 12

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

From: fabio.lombardelli on
{ Rejection reasons: overquoted with top-posting & quoted banner. -mod }

yes, it's the right behavior maybe.
But I can't understand why it works with methods and not with
typedefs....

red floyd ha scritto:

> fabio.lombardelli(a)gmail.com wrote:
> > Hi all,
> > can somebody explain me why this piece of code doesn't compile?
> > In particular, why the compiler (on Base<Derived> class) can see _fun,
> > and why it can't see _DType?
> >
> > template <typename D>
> > struct Base
> > {
> > typedef typename D::_DType DType;
> >
> > void fun()
> > {
> > static_cast<D*>(this)->_fun();
> > }
> > };
> >
> > struct Derived : public Base<Derived>
> > {
> > typedef int _DType;
> >
> > void _fun() {}
> > };
> >
> > Maybe Base<Derived> class knows Derived class just as a forward
> > declaration.
> > But if it is so, why it can see the method _fun?
> >
>
> FWIW, Comeau online complains about an incomplete type at the point of
> instantiation.
>
> "ComeauTest.c", line 4: error: incomplete type is not allowed
> typedef typename D::_DType DType;
> ^
> detected during instantiation of class "Base<D> [with
> D=Derived]" at
> line 12
>
> --
> [ See http://www.gotw.ca/resources/clcm.htm for info about ]
> [ comp.lang.c++.moderated. First time posters: Do this! ]


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

From: David Abrahams on
fabio.lombardelli(a)gmail.com writes:

> Hi all,
> can somebody explain me why this piece of code doesn't compile?
> In particular, why the compiler (on Base<Derived> class) can see _fun,
> and why it can't see _DType?
>
> template <typename D>
> struct Base
> {
> typedef typename D::_DType DType;
>
> void fun()
> {
> static_cast<D*>(this)->_fun();
> }
> };
>
> struct Derived : public Base<Derived>
> {
> typedef int _DType;
>
> void _fun() {}
> };
>
> Maybe Base<Derived> class knows Derived class just as a forward
> declaration.

Exactly.

> But if it is so, why it can see the method _fun?

Declarations in a class are instantiated all at once, but definitions
(e.g. the bodies of member functions) are instantiated only when they
are used. You can rewrite the example as:

template <typename D>
struct Base
{
// uncomment for error
// typedef typename D::_DType DType;
void fun();
};

struct Derived : public Base<Derived>
{
typedef int _DType;

void _fun() {}
};

template <typename D>
void Base<D>::fun()
{
static_cast<D*>(this)->_fun();
}

Which should make it pretty clear why fun parses OK. Now you can
imagine transforming fun into a non-member, just to make it extra
clear that it is instantiated later.

template <typename D>
void fun(Base<D>* p)
{
static_cast<D*>(p)->_fun();
}

Regards,

--
Dave Abrahams
Boost Consulting
www.boost-consulting.com

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

From: Ian McCulloch on
fabio.lombardelli(a)gmail.com wrote:

> Hi all,
> can somebody explain me why this piece of code doesn't compile?
> In particular, why the compiler (on Base<Derived> class) can see _fun,
> and why it can't see _DType?
>
> template <typename D>
> struct Base
> {
> typedef typename D::_DType DType;
>
> void fun()
> {
> static_cast<D*>(this)->_fun();
> }
> };
>
> struct Derived : public Base<Derived>
> {
> typedef int _DType;
>
> void _fun() {}
> };
>
> Maybe Base<Derived> class knows Derived class just as a forward
> declaration.

Yes, to define Derived, it requires that Base<Derived> as *already* been
instantiated. This implies that Derived is an incomplete type, as far as
Base is concerned.

> But if it is so, why it can see the method _fun?

The answer here (someone please correct me if I am wrong!) is that the point
of instantiation of a member is not coincident with the point of
instantiation of the class itself. Members of a class template are only
instantiated if they are actually used. And at the point of using
Base<Dreived>::fun(), it will (normally) be after the declaration of
Derived.

[
By the way, names starting with an underscore followed by a capital letter
are reserved for the compiler implementation, you should never use such
names yourself. You should take this seriously: a few months ago a
colleague of mine came to me with a weird compiler error, which turned out
to be a updated release of g++ that suddenly defined a macro _P - which my
coleague had used unfortunately as as the name of a local variable. It
took a while to figure out what the error message meant ;-)
]

The solution to what you want is to use a traits type.

template <typename D> struct DerivedTraits {};

template <typename D>
struct Base
{
typedef typename DerivedTraits<D>::DType DType;
// ...
};

struct Derived;
template <> struct DerivedTraits<Derived>
{
typedef int DType;
};

struct Derived : Base<Derived>
{
typedef Base<Derived>::DType DType; // both these
typedef DerivedTraits<Derived>::DType DType; // are equivalent
};

HTH,
Ian McCulloch


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