From: fabio.lombardelli on 18 Dec 2006 11:50 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 18 Dec 2006 14:43 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 18 Dec 2006 16:24 { 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 18 Dec 2006 20:55 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 19 Dec 2006 07:27 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! ]
|
Next
|
Last
Pages: 1 2 Prev: Why no std::back_insert_iterator::value_type? Next: Exception alternatives |