How to you access a nested template class?

A

Adam Nielsen

Hi all,

I'm a bit confused about the syntax used to access a nested template
class. Essentially I have a bunch of class types to represent different
types of records in a database, and I want to store some cache data for
each datatype. The simplified code below demonstrates my issue - I
think I understand why it doesn't work as is (the structure only
declares the storage, I need to instantiate it for each template type)
but I'm not sure how to actually go about doing that.

Any pointers would be appreciated!

Thanks,
Adam.


class RecordTypeA { };
class RecordTypeB { };

class Main {

private:

template <typename T>
struct CacheData {
int i;
};

public:

template <typename T>
void set(T t, int x)
{
// Store some type-specific data for record type T
this->CacheData<T>::i = x;
}

};

int main(void)
{
RecordTypeA A;
RecordTypeB B;
Main m;
m.set(A, 1);
m.set(B, 2);

// At this point, I want this to be the case:
// m.CacheData<A>::i == 1
// m.CacheData<B>::i == 2

return 0;
}
 
K

Kai-Uwe Bux

Adam said:
Hi all,

I'm a bit confused about the syntax used to access a nested template
class. Essentially I have a bunch of class types to represent different
types of records in a database, and I want to store some cache data for
each datatype. The simplified code below demonstrates my issue - I
think I understand why it doesn't work as is (the structure only
declares the storage, I need to instantiate it for each template type)
but I'm not sure how to actually go about doing that.

Any pointers would be appreciated!

Thanks,
Adam.


class RecordTypeA { };
class RecordTypeB { };

class Main {

private:

template <typename T>
struct CacheData {
int i;
};

This declares a type.
public:

template <typename T>
void set(T t, int x)
{
// Store some type-specific data for record type T
this->CacheData<T>::i = x;

There is no member variable this->CacheData said:
}

};

int main(void)
{
RecordTypeA A;
RecordTypeB B;
Main m;
m.set(A, 1);

You cannot call set that way. Templates do not make types into valid
arguments for functions.
m.set(B, 2);

// At this point, I want this to be the case:
// m.CacheData<A>::i == 1
// m.CacheData<B>::i == 2

return 0;
}


You may want to ponder about the following:


#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

int main ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}



Best

Kai-Uwe Bux
 
Joined
Oct 4, 2007
Messages
4
Reaction score
0
Clearly templates are not the solution to your problem.
Come out of generic programming mindset here. Use a map for each type.
I think you are running into a serious design error.
 
A

Alf P. Steinbach

* Kai-Uwe Bux:
* Adam Nielsen:

This declares a type.


There is no member variable this->CacheData<T> since CacheData<T> is a type.

You mean, since class 'Main' does not derive from that type.
You cannot call set that way. Templates do not make types into valid
arguments for functions.

Uh, there are no types as arguments here.

But you're right that it seems the OP is confusing types with data members.


Cheers,

- Alf
 
A

Adam Nielsen

You may want to ponder about the following:
#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

int main ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

That makes sense, thanks for the example! Out of curiosity, is there
any way of doing this without using a runtime lookup? Something like a
'template-variable', if there were such a thing.

Cheers,
Adam.
 
K

Kai-Uwe Bux

Adam said:
You may want to ponder about the following:


#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

int main ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

That makes sense, thanks for the example! Out of curiosity, is there
any way of doing this without using a runtime lookup? Something like a
'template-variable', if there were such a thing.

You can do this for static data (e.g., you can have such data on a per class
basis):

#include <cassert>

template < typename T >
struct static_typemap {

template < typename A >
static
T & value ( void ) {
static T data;
return ( data );
}

};


int main ( void ) {

static_typemap<int>::value<char>() = 1;
static_typemap<int>::value<int>() = 2;

assert( static_typemap<int>::value<char>() == 1 );
assert( static_typemap<int>::value<int>() == 2 );

}


_If_ we had templated virtual member functions, we could do such tricks on a
per object basis (and all sorts of other cool stuff).


Best

Kai-Uwe Bux
 
A

Adam Nielsen

You may want to ponder about the following:
#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

int main ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

Hi Kai-Uwe,

I've just started implementing this design in my code, but I can't
figure out why it won't work inside a template.

For example, if I delete your main() function above and replace the code
with this:

template <typename X>
int m ( void ) {
typemap<int> table;
table.value<char>() = 2; // line 59 in the error below
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

int main ( void ) {
m<int>();
}

When I compile it I end up with this:

t4.cpp: In function `int m()':
t4.cpp:59: error: parse error before `>' token
t4.cpp:60: error: parse error before `>' token
t4.cpp:61: error: parse error before `>' token
t4.cpp:62: error: parse error before `>' token

I don't understand why this happens, as I didn't think it mattered
*where* you used the code. Is there something special you must do in
this situation?

Thanks again,
Adam.
 
K

Kai-Uwe Bux

Adam said:
You may want to ponder about the following:


#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

int main ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

Hi Kai-Uwe,

I've just started implementing this design in my code, but I can't
figure out why it won't work inside a template.

For example, if I delete your main() function above and replace the code
with this:

template <typename X>
int m ( void ) {
typemap<int> table;
table.value<char>() = 2; // line 59 in the error below
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

int main ( void ) {
m<int>();
}

When I compile it I end up with this:

t4.cpp: In function `int m()':
t4.cpp:59: error: parse error before `>' token
t4.cpp:60: error: parse error before `>' token
t4.cpp:61: error: parse error before `>' token
t4.cpp:62: error: parse error before `>' token

I don't understand why this happens, as I didn't think it mattered
*where* you used the code. Is there something special you must do in
this situation?

I cannot reproduce the error. The code you posted compiles for me. This
maybe due to you giving instructions on how to create the code from the
present pieces instead of posting a complete piece.


Best

Kai-Uwe Bux
 
A

Adam Nielsen

I cannot reproduce the error. The code you posted compiles for me. This
maybe due to you giving instructions on how to create the code from the
present pieces instead of posting a complete piece.

That's strange then - well here is the exact code I'm compiling.
Perhaps if someone else using GCC can test it as well to see whether
it's a compiler issue?

#include <cassert>
#include <map>

template < typename T >
class typemap {

typedef void (*id) ( void );

template < typename A >
static
void type_identifier ( void ) {}

std::map< id, T > data;

public:

template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}

template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}

};

template <typename X>
int m ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}

int main ( void ) {
m<int>();
}

$ g++ -o t t.cpp
t.cpp: In function `int m()':
t.cpp:32: syntax error before `>' token
t.cpp:33: syntax error before `>' token
t.cpp:34: syntax error before `>' token
t.cpp:35: syntax error before `>' token
$ g++ --version
g++-gcc-3.2.3 (GCC) 3.2.3

I've also tried it with GCC 3.3.4 with the same result.

Cheers,
Adam.
 
K

Kai-Uwe Bux

Adam said:
I cannot reproduce the error. The code you posted compiles for me. This
maybe due to you giving instructions on how to create the code from the
present pieces instead of posting a complete piece.

That's strange then - well here is the exact code I'm compiling.
Perhaps if someone else using GCC can test it as well to see whether
it's a compiler issue? [code snipped]
I've also tried it with GCC 3.3.4 with the same result.

Thanks for the complete code. It compiles for me with g++ (gcc 3.4.6 and
4.1.1).


Best

Kai-Uwe Bux
 
J

James Kanze

That's strange then - well here is the exact code I'm
compiling. Perhaps if someone else using GCC can test it as
well to see whether it's a compiler issue?
#include <cassert>
#include <map>
template < typename T >
class typemap {
typedef void (*id) ( void );
template < typename A >
static
void type_identifier ( void ) {}
std::map< id, T > data;
public:
template < typename A >
T const & value ( void ) const {
return ( data[ &type_identifier<A> ] );
}
template < typename A >
T & value ( void ) {
return ( data[ &type_identifier<A> ] );
}
};
template <typename X>
int m ( void ) {
typemap<int> table;
table.value<char>() = 2;
table.value<int>() = 1;
assert( table.value<char>() == 2 );
assert( table.value<int>() == 1 );
}
int main ( void ) {
m<int>();
}
$ g++ -o t t.cpp
t.cpp: In function `int m()':
t.cpp:32: syntax error before `>' token
t.cpp:33: syntax error before `>' token
t.cpp:34: syntax error before `>' token
t.cpp:35: syntax error before `>' token
$ g++ --version
g++-gcc-3.2.3 (GCC) 3.2.3
I've also tried it with GCC 3.3.4 with the same result.

I get the same errors with 3.2.3, but it compiles with g++
4.1.0. If you replace typemap<int> with typemap<X> in the first
line of m, you get errors with both compilers, of course.
Changing each of the function calls to:

table.template value<...>...

works in all cases however.

It's an interesting case, since it's the only case I know of off
hand in which a (non-instantiated) template definition can
trigger the instantiation of another template. Apparently, g++
pre-4.0 is not instantiating typemap<int> here, and so is
treating the < as if it were the less than operator. (Note that
in the case of typemap<X>, the context is dependent, so you are
required to tell the compiler when the name in question -- here,
value -- is a type or a template.)
 
A

Adam Nielsen

Changing each of the function calls to:
table.template value<...>...

works in all cases however.

Ah, that's excellent - that's saved me a compiler upgrade :)

Cheers,
Adam.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,781
Messages
2,569,615
Members
45,296
Latest member
HeikeHolli

Latest Threads

Top