From: pfultz2 on
I seem to have a problem with CRTP and typedefs, here is a sample
code:

template<class B>
class Sequence
{
public:
typedef typename B::ElementType ElementType;
}

template<class T>
class Container
{
public:
typedef T ElementType;
}

Containter<char> test;

but the compiler says that Container<char>::ElementType doesnt exist?
is it possible to refer to subtypes using CRTP? or perhaps i have a
error some other place in my code?
is there a way to forward declare the type and the subtypes like this:

template<class T>
class Container;

//Then forward declare subtype here
template<class T>
class Containter<T>::ElementType;

Or maybe there is another way, thanks

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

From: pfultz2 on
On Feb 1, 4:04 pm, pfultz2 <pful...(a)yahoo.com> wrote:
> I seem to have a problem with CRTP and typedefs, here is a sample
> code:
>
> template<class B>
> class Sequence
> {
> public:
> typedef typename B::ElementType ElementType;
>
> }
>
> template<class T>
> class Container
> {
> public:
> typedef T ElementType;
>
> }
>
> Containter<char> test;
>
> but the compiler says that Container<char>::ElementType doesnt exist?
> is it possible to refer to subtypes using CRTP? or perhaps i have a
> error some other place in my code?
> is there a way to forward declare the type and the subtypes like this:
>
> template<class T>
> class Container;
>
> //Then forward declare subtype here
> template<class T>
> class Containter<T>::ElementType;
>
> Or maybe there is another way, thanks

{ edits: quoted banner removed. please remove irrelevant material before
posting. -mod }

I dont know if i made it clear in the code, let me try to rewrite it:

template<class B>
class Sequence
{
public:
typedef typename B::Iterator Iterator;
typedef typename B::ElementType ElementType;

}

template<class T>
class Container : public Sequence<Container<T>>
{
public:
typedef T ElementType;
class Iterator
{
};

}

Now i get an error saying that B::Iterator and B::ElementType doesnt
exist. Does anyone know of some workarounds? I need to use the those
types in various places, I could infer the type from the method I call
using typeof or decltyp. I need to use it in the return types in
several places like this:
ElementType First()
{
return this->Derived().GetIterator().First();
}

ReverseIterator<Iterator> Reverse()
{
return ReverseIterator<Iterator>(this->Derived().GetIterator());
}

Where the Derived() method casts the this pointer to the derived
class.
Is this even possible? Or is there a better way to do this? The only
other way i can think of is to use macros, but this is not very nice,
and is harder to mantain.
thanks


--
[ 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 Feb 1, 3:04 pm, pfultz2 <pful...(a)yahoo.com> wrote:
> I seem to have a problem with CRTP and typedefs, here is a sample
> code:

Poor sample, as it is invalid code (missing semicolons, has typos,
etc),
it doesn't show any CRTP at all, and therefore does not show what you
are
describing.

Corrected: (Educated guess)

template<class B>
class Sequence
{
public:
typedef typename B::ElementType ElementType;
};

template<class T>
class Container : public Sequence<Container<T> >
{
public:
typedef T ElementType;
};

Container<char> test;


The problem, regardless, is that at the point where Container<T>
inherits from Sequence,
it is an incomplete type and is thus not able to be interrogated for
nested types.

The easiest solution is to pass up another template parameter for the
element type:

template<class Derived, typename ElementT>
class Sequence
{
public:
typedef ElementT ElementType;
};

template<class T>
class Container : public Sequence<Container<T>, T>
{
// ...
};


Chris




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

From: Johannes Schaub (litb) on
pfultz2 wrote:

> I seem to have a problem with CRTP and typedefs, here is a sample
> code:
>
> template<class B>
> class Sequence
> {
> public:
> typedef typename B::ElementType ElementType;
> }
>
> template<class T>
> class Container
> {
> public:
> typedef T ElementType;
> }
>
> Containter<char> test;
>
> but the compiler says that Container<char>::ElementType doesnt exist?
> is it possible to refer to subtypes using CRTP? or perhaps i have a
> error some other place in my code?
> is there a way to forward declare the type and the subtypes like this:
>
> template<class T>
> class Container;
>
> //Then forward declare subtype here
> template<class T>
> class Containter<T>::ElementType;
>
> Or maybe there is another way, thanks
>

I'm assuming you actually have an inheritance relationship, and forgot to
write that in your testcase. Well, at the point "Sequence<Container>" is
instantiated (which happens immediately when the base class name is seen),
Container::ElementType has not yet been declared, and so the instantiation
of the typedef declaration in Sequence will fail to find it.

You can put that as a template argument. What about

template<typename T, typename Typedefs>
class Sequence {
typedef typename Typedefs::ElementType ElementType;
// ...
};



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

From: Jeff Schwab on
pfultz2 wrote:
> I seem to have a problem with CRTP and typedefs, here is a sample
> code:
>
> template<class B>
> class Sequence
> {
> public:
> typedef typename B::ElementType ElementType;
> }
>
> template<class T>
> class Container
> {
> public:
> typedef T ElementType;
> }
>
> Containter<char> test;

There is no CRTP in that code, you're missing two semicolons, and there
is no such template as Containter.

> but the compiler says that Container<char>::ElementType doesnt exist?
> is it possible to refer to subtypes using CRTP? or perhaps i have a
> error some other place in my code?

It's impossible to tell you what the error is without seeing the actual
code, or at least the actual diagnostic message from the compiler. The
following is valid C++ that does what you seem to want:

namespace {

template<class B>
struct sequence
{
typedef typename B::element_type element_type;
};

template<class T>
struct container
{
typedef T element_type;
};

typedef container<char> container_t;
typedef sequence<container_t> sequence_t;

container_t const chars = container_t( );
sequence_t const containers = sequence_t( );
}

#include <cassert>

int main() {
assert(sizeof(sequence_t::element_type) == 1);
}

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