By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,743 Members | 1,028 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,743 IT Pros & Developers. It's quick & easy.

Compilation problem with templates

P: n/a
Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue> {
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?

Thanks
Jerome
Apr 26 '07 #1
Share this Question
Share on Google+
9 Replies


P: n/a
Jerome Durand wrote:
Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue{
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?
It can be that the compiler is trying to resolve 'derived::valueType'
too soon (at the time when it encounters the 'typedef' in 'Base', the
'derived' is not completely defined yet. The behaviour of compilers
in this matter can differ somewhat, but the most concervative will
likely choke because 'derived' is incomplete by the time 'Base'
instantiation is attemtped. You might consider replacing the 'typedef'
dance with normal type processing:

template<typename valueTypestruct Base {
virtual valueType Value() = 0;
};

struct CharValue : Base<char{
char Value() { return 'a'; }
};

...

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #2

P: n/a
Victor Bazarov a écrit :
Jerome Durand wrote:
>Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue{
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?

It can be that the compiler is trying to resolve 'derived::valueType'
too soon (at the time when it encounters the 'typedef' in 'Base', the
'derived' is not completely defined yet. The behaviour of compilers
in this matter can differ somewhat, but the most concervative will
likely choke because 'derived' is incomplete by the time 'Base'
instantiation is attemtped. You might consider replacing the 'typedef'
dance with normal type processing:

template<typename valueTypestruct Base {
virtual valueType Value() = 0;
};

struct CharValue : Base<char{
char Value() { return 'a'; }
};

...

V
This is not really an option because I intend to have
several functions declared in base with different return
types which should depend on types defined in derived...

Jerome
Apr 26 '07 #3

P: n/a
Jerome Durand wrote:
Victor Bazarov a écrit :
>Jerome Durand wrote:
>>Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue{
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?

It can be that the compiler is trying to resolve 'derived::valueType'
too soon (at the time when it encounters the 'typedef' in 'Base', the
'derived' is not completely defined yet. The behaviour of compilers
in this matter can differ somewhat, but the most concervative will
likely choke because 'derived' is incomplete by the time 'Base'
instantiation is attemtped. You might consider replacing the
'typedef' dance with normal type processing:

template<typename valueTypestruct Base {
virtual valueType Value() = 0;
};

struct CharValue : Base<char{
char Value() { return 'a'; }
};

...

V

This is not really an option because I intend to have
several functions declared in base with different return
types which should depend on types defined in derived...
Then you're SOL since those types are members of the class which
is not going to be fully defined by the time Base is instantiated.
Catch 22.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Apr 26 '07 #4

P: n/a
Victor Bazarov a écrit :
Jerome Durand wrote:
>Victor Bazarov a écrit :
>>Jerome Durand wrote:
Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue{
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?
It can be that the compiler is trying to resolve 'derived::valueType'
too soon (at the time when it encounters the 'typedef' in 'Base', the
'derived' is not completely defined yet. The behaviour of compilers
in this matter can differ somewhat, but the most concervative will
likely choke because 'derived' is incomplete by the time 'Base'
instantiation is attemtped. You might consider replacing the
'typedef' dance with normal type processing:

template<typename valueTypestruct Base {
virtual valueType Value() = 0;
};

struct CharValue : Base<char{
char Value() { return 'a'; }
};

...

V
This is not really an option because I intend to have
several functions declared in base with different return
types which should depend on types defined in derived...

Then you're SOL since those types are members of the class which
is not going to be fully defined by the time Base is instantiated.
Catch 22.

V
Thank you Victor.

I did something a little differently to break the incomplete definition
dependency... Could have done it without an intermediate class, but I
felt it was better like this:
template <class aderived, class avaluetypestruct DerivedDescription {
typedef aderived derived;
typedef avaluetype valueType;

};
template <typename derivedDescriptionstruct Base{
typedef typename derivedDescription::valueType valueType;
virtual valueType Value() = 0;
};
struct CharValue: Base< DerivedDescription<CharValue, char{
typedef char valueType ;
valueType Value() {return 'a';}
};

struct IntValue: Base<DerivedDescription<IntValue, int>>{
typedef int valueType ;
valueType Value() {return 1234;}
};
Jerome

Apr 26 '07 #5

P: n/a
On Apr 26, 7:23 am, Jerome Durand <j.dur...@def2shoot.comwrote:
Hello,

I'm trying to write something along the following lines
but I cannot get this to compile.

template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue {
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'

Could someone tell me what is wrong with this?
You're effectively trying to use CharValue and IntValue before they're
defined. Why not simplify it like this:

template <typename Tstruct Base {
typedef T valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<char>{
valueType Value() {return 'a';}

};

struct IntValue: Base<int {
valueType Value() {return 1234;}
};

Cheers! --M

Apr 26 '07 #6

P: n/a
On Apr 26, 7:23 am, Jerome Durand <j.dur...@def2shoot.comwrote:
I'm trying to write something along the following lines
but I cannot get this to compile.

template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue {
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'

Could someone tell me what is wrong with this?
You're effectively trying to use CharValue and IntValue before they're
defined. Why not simplify it like this:

template <typename Tstruct Base {
typedef T valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<char>{
valueType Value() {return 'a';}

};

struct IntValue: Base<int {
valueType Value() {return 1234;}
};

Cheers! --M

Apr 26 '07 #7

P: n/a
mlimber a écrit :
On Apr 26, 7:23 am, Jerome Durand <j.dur...@def2shoot.comwrote:
>I'm trying to write something along the following lines
but I cannot get this to compile.

template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}

};

struct IntValue: Base<IntValue {
typedef int valueType ;
valueType Value() {return 1234;}
};

The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'

Could someone tell me what is wrong with this?

You're effectively trying to use CharValue and IntValue before they're
defined. Why not simplify it like this:

template <typename Tstruct Base {
typedef T valueType;
virtual valueType Value() = 0;
};

struct CharValue: Base<char>{
valueType Value() {return 'a';}

};

struct IntValue: Base<int {
valueType Value() {return 1234;}
};

Cheers! --M
because this is a trimmed down version of my problem,
where there's more than a single function and hence
more than a single return type required.

-J-
Apr 26 '07 #8

P: n/a
On Apr 26, 1:23 pm, Jerome Durand <j.dur...@def2shoot.comwrote:
I'm trying to write something along the following lines
but I cannot get this to compile.
template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};
struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}
};
struct IntValue: Base<IntValue {
typedef int valueType ;
valueType Value() {return 1234;}
};
The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
Could someone tell me what is wrong with this?
The error message could be clearer (mentionning e.g. incomplete
class), but if you think about how templates and class
definitions work, it should be obvious that this is impossible.
The use of the template as a base class triggers instantiation,
since a class must be complete to be used as a base, and
(§14.7.1/4) "A class template specialization is implicitly
instantiated if the class type is used in a context that
requires a completelydefined object type or if the completeness
of the class type might affect the semantics of the program."
(It's logical, really... what good would implicit instantiation
be otherwise.) In the template, derived::valueType is a
dependant name (obviously), so is resolved at the point of
instantiation. And (§14.6.4.1/3) "For a class template
specialization, [...] the point of instantiation for such a
specialization immediately precedes the namespace scope
declaration or definition that refers to the specialization."
Again, this is the only logical solution: you can't instantiate
(define) a class in the middle of your declaration, so it has to
be either before or after, and if it is after, you still don't
have a complete class to use as a base. Of course, if the point
of instantiation is before the definition of the class which
derives from the template, the contents of that class are not
accessible in the template.

Your basic problem is that you have created a cyclic
dependency. As written, Base can only be instantiated on a
complete class (since it uses contents of the class). And you
need an already instantiated Base in order to define the derived
class. The only solution is to break the cycle: make Base
independant of the derived class. In this case, for example,
you might pass valueType as a template argument, e.g.:

template< typename ValueType struct Base {
virtual ValueType value() = 0 ;
} ;

struct CharValue : Base< char { /* ... */ } ;
// etc.

If in your real code, this entails two or three parameters to
Base, so be it. If the number of parameters starts really
getting out of hand, you might also consider using traits. This
does make using Base somewhat more complicated, but it allows
considerably more flexibility.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Apr 27 '07 #9

P: n/a
James Kanze a écrit :
On Apr 26, 1:23 pm, Jerome Durand <j.dur...@def2shoot.comwrote:
>I'm trying to write something along the following lines
but I cannot get this to compile.
> template <typename derivedstruct Base {
typedef typename derived::valueType valueType;
virtual valueType Value() = 0;
};
> struct CharValue: Base<CharValue>{
typedef char valueType ;
valueType Value() {return 'a';}
};
> struct IntValue: Base<IntValue {
typedef int valueType ;
valueType Value() {return 1234;}
};
>The compiler outputs (first error only):
Error 1: 'valueType' : is not a member of CharValue'
>Could someone tell me what is wrong with this?

The error message could be clearer (mentionning e.g. incomplete
class), but if you think about how templates and class
definitions work, it should be obvious that this is impossible.
The use of the template as a base class triggers instantiation,
since a class must be complete to be used as a base, and
(§14.7.1/4) "A class template specialization is implicitly
instantiated if the class type is used in a context that
requires a completelydefined object type or if the completeness
of the class type might affect the semantics of the program."
(It's logical, really... what good would implicit instantiation
be otherwise.) In the template, derived::valueType is a
dependant name (obviously), so is resolved at the point of
instantiation. And (§14.6.4.1/3) "For a class template
specialization, [...] the point of instantiation for such a
specialization immediately precedes the namespace scope
declaration or definition that refers to the specialization."
Again, this is the only logical solution: you can't instantiate
(define) a class in the middle of your declaration, so it has to
be either before or after, and if it is after, you still don't
have a complete class to use as a base. Of course, if the point
of instantiation is before the definition of the class which
derives from the template, the contents of that class are not
accessible in the template.

Your basic problem is that you have created a cyclic
dependency. As written, Base can only be instantiated on a
complete class (since it uses contents of the class). And you
need an already instantiated Base in order to define the derived
class. The only solution is to break the cycle: make Base
independant of the derived class. In this case, for example,
you might pass valueType as a template argument, e.g.:

template< typename ValueType struct Base {
virtual ValueType value() = 0 ;
} ;

struct CharValue : Base< char { /* ... */ } ;
// etc.

If in your real code, this entails two or three parameters to
Base, so be it. If the number of parameters starts really
getting out of hand, you might also consider using traits. This
does make using Base somewhat more complicated, but it allows
considerably more flexibility.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


all of this sounds very sensible. I don't have the standard, from
which I could have read where the point of instantiation for the
template is required to be, and it does make sense.

As you guessed, my real code needs more than a single parameter,
I finally found a solution on my own, which I find more tedious,
but works. I'll check how traits can be of use here...

I now have a solution to my problem and an explanation for it.
The latter is more precious than the former, it should later
help me to clear away from the same mistake in the first place.

Thank you James!
Jerome


Apr 27 '07 #10

This discussion thread is closed

Replies have been disabled for this discussion.