Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Curiously Recurring Template Problem

Reply
Thread Tools

Curiously Recurring Template Problem

 
 
Martin MacRobert
Guest
Posts: n/a
 
      07-26-2004
Hi Gang,
The following code does not compile, but I can't figure out why. The
compiler complains that the CuriouslyDerivedType (CRDerived) does not
publish the "value_type", yet in fact the class CRDerived does.

Is there any way of making the code work? I would like functions to
accept a CRBase template, and the CRBase must be able to deduce the
"value_type" of the function that it is "curiously calling".

Thanks.
Martin

------snip here 8< ------
template <typename CurioslyDerivedType>
struct CRBase
{
typedef typename CurioslyDerivedType::value_type value_type;

const CurioslyDerivedType& derived() const
{
return static_cast<const CurioslyDerivedType&>(*this);
}

value_type invoke() const
{
return derived().foo();
}
};

struct CRDerived:
public CRBase< CRDerived >
{
typedef int value_type;

int foo() const
{
return 1234;
}
};

template <typename CurioslyDerivedType>
typename CRBase<CurioslyDerivedType>::value_type
invoke(const CRBase<CurioslyDerivedType>& c)
{
return cr.invoke();
}

int main()
{
CRDerived c;
int result = invoke(c);
return 0;
}


------snip here 8< ------

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      07-26-2004
Martin MacRobert wrote:
> The following code does not compile, but I can't figure out why. The
> compiler complains that the CuriouslyDerivedType (CRDerived) does not
> publish the "value_type", yet in fact the class CRDerived does.
>
> Is there any way of making the code work? I would like functions to
> accept a CRBase template, and the CRBase must be able to deduce the
> "value_type" of the function that it is "curiously calling".


First of all, it has to figure out what 'value_type' is. In your
code it is generally impossible. You should think of making that
'value_type' thing in CRBase a separate template argument. Then
you break that cycle when the definition of 'value_type' in CRBase
depends on the definition of 'value_type' in the derived class,
which hasn't been defined yet.

>
> Thanks.
> Martin
>
> ------snip here 8< ------
> template <typename CurioslyDerivedType>
> struct CRBase
> {
> typedef typename CurioslyDerivedType::value_type value_type;
>
> const CurioslyDerivedType& derived() const
> {
> return static_cast<const CurioslyDerivedType&>(*this);
> }
>
> value_type invoke() const
> {
> return derived().foo();
> }
> };
>
> struct CRDerived:
> public CRBase< CRDerived >


At this point it tries to instantiate CRBase with CRDerived as the
template argument. CRBase attempts to find 'value_type' member of
its template argument. But CRDerived (the actual argument) hasn't
been defined yet (at this point). So, no 'value_type' member in it
exists (the compiler hasn't got to that line yet, two lines down).

That's why it doesn't compile.

> {
> typedef int value_type;
>
> int foo() const
> {
> return 1234;
> }
> };
>
> template <typename CurioslyDerivedType>
> typename CRBase<CurioslyDerivedType>::value_type
> invoke(const CRBase<CurioslyDerivedType>& c)
> {
> return cr.invoke();
> }
>
> int main()
> {
> CRDerived c;
> int result = invoke(c);
> return 0;
> }


try

template<typename CuriouslyDerivedType, typename T> class CRBase
{
typedef T value_type;
....
};

struct CRDerived : public CRBase<CRDerived, int>
{
typedef int value_type; // if you need it inside, otherwise better
// to inherit it from CRBase so that 'int'
// is only mentioned once: in the angle
// brackets of the CRBase specialisation
...
};

Victor
 
Reply With Quote
 
 
 
 
=?ISO-8859-1?Q?=22Daniel_Kr=FCgler_=28ne_Spangenberg=29=22?=
Guest
Posts: n/a
 
      07-26-2004
Hello Martin MacRobert,

Martin MacRobert schrieb:

>Hi Gang,
>The following code does not compile, but I can't figure out why. The
>compiler complains that the CuriouslyDerivedType (CRDerived) does not
>publish the "value_type", yet in fact the class CRDerived does.
>
>Is there any way of making the code work? I would like functions to
>accept a CRBase template, and the CRBase must be able to deduce the
>"value_type" of the function that it is "curiously calling".
>
>Thanks.
>Martin
>
>------snip here 8< ------
>template <typename CurioslyDerivedType>
>struct CRBase
>{
> typedef typename CurioslyDerivedType::value_type value_type;
>
> const CurioslyDerivedType& derived() const
> {
> return static_cast<const CurioslyDerivedType&>(*this);
> }
>
> value_type invoke() const
> {
> return derived().foo();
> }
>};
>
>struct CRDerived:
> public CRBase< CRDerived >
>{
> typedef int value_type;
>
> int foo() const
> {
> return 1234;
> }
>};
>
>template <typename CurioslyDerivedType>
>typename CRBase<CurioslyDerivedType>::value_type
>invoke(const CRBase<CurioslyDerivedType>& c)
>{
> return cr.invoke();
>}
>
>int main()
>{
> CRDerived c;
> int result = invoke(c);
> return 0;
>}
>
>
>------snip here 8< ------
>


The compiler is right, because CRDerived is still undefined at the point
of the definition of
the class CRBase. If you want to take advantage of CRTP you are limited
to uses of the
derived class which don't need its actual definition, e.g. inside member
functions. One
possibility is to move the static assertion into a member function of
CRBase, which **must**
be defined:

template <typename CurioslyDerivedType>
struct CRBase
{
~CRBase() {
typedef typename CurioslyDerivedType::value_type value_type;
}

..
};

Regrettably this does not help you in case of your member function:

value_type invoke() const;

The only workaround for this seems to be a further template parameter:

template <typename CurioslyDerivedType, typename ValueTypeT>
struct CRBase
{
typedef ValueTypeT value_type;

~CRBase() {
// This test ensures, that
// - CurioslyDerivedType provides a value_type name
// - that CurioslyDerivedType::value_type is identical to ValueTypeT
BOOST_STATIC_ASSERT(boost::is_same<typename CurioslyDerivedType::value_type, value_type>::value);
}
};

struct CRDerived:
public CRBase< CRDerived, int >
{
typedef int value_type;

int foo() const
{
return 1234;
}
};


Greetings from Bremen,

Daniel Krügler



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
Reply With Quote
 
Marco Manfredini
Guest
Posts: n/a
 
      07-26-2004
Martin MacRobert wrote:

> Hi Gang,
> The following code does not compile, but I can't figure out why. The
> compiler complains that the CuriouslyDerivedType (CRDerived) does not
> publish the "value_type", yet in fact the class CRDerived does.


That's because CRDerived isn't fully defined yet, when the compiler
instantiates the CRBase<> template or as a rule of thumb: He hasn seen
seen all of the body yet.

A workaround could be a helper class:

// default definition of value_type_of<T>
template<class T> struct value_type_of
{
typedef typename T::value_type type;
};

// definition of CRBase<T>...

// specialization for CRDerived, a kind of forward-declare if you want..
struct CRDerived;
template<> struct value_type_of<CRDerived>{ typedef int type; };

struct CRDerived:
public CRBase< CRDerived >
{
typedef value_type_of<CRDerived> value_type;
...
};

Marco


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
 
Reply With Quote
 
kwikius
Guest
Posts: n/a
 
      07-26-2004
http://www.velocityreviews.com/forums/(E-Mail Removed) (Martin MacRobert) wrote in message news:<(E-Mail Removed). com>...
> Hi Gang,
> The following code does not compile, but I can't figure out why. The
> compiler complains that the CuriouslyDerivedType (CRDerived) does not
> publish the "value_type", yet in fact the class CRDerived does.
>
> Is there any way of making the code work? I would like functions to
> accept a CRBase template, and the CRBase must be able to deduce the
> "value_type" of the function that it is "curiously calling".
>
> Thanks.
> Martin
>

#include<iostream>
template< typename X>
struct traits;

template <typename CurioslyDerivedType>
struct CRBase
{
typedef typename traits<CurioslyDerivedType>::value_type value_type;
const CurioslyDerivedType& derived() const
{
return static_cast<const CurioslyDerivedType&>(*this);
}

value_type invoke() const
{
return derived().foo();
}
};

struct CRDerived;
template<>
struct traits<CRDerived>{ typedef int value_type;};
struct CRDerived : public CRBase< CRDerived >
{
typedef traits<CRDerived>::value_type value_type;

value_type foo() const
{
return 1234;
}
};

template <typename CurioslyDerivedType>
typename traits<CurioslyDerivedType>::value_type
invoke(const CRBase<CurioslyDerivedType>& c)
{
return c.invoke();
}

int main()
{
CRDerived c;
int result = invoke(c);
std::cout << result <<'\n';
return 0;
}

regards
Andy Little

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

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Curiously Recurring Template Pattern chsalvia@gmail.com C++ 4 07-11-2007 01:22 PM
A class scope allocator using the Curiously Recursive Template Pattern AndrewD C++ 4 01-26-2007 11:32 PM
Curiously recurring template pattern iuweriur C++ 15 07-12-2004 08:48 PM
curiously recurring template pattern problem Denis Remezov C++ 7 04-07-2004 10:50 AM
recurring template problem velthuijsen C++ 2 04-07-2004 08:52 AM



Advertisments