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

map containing a string key and a templated value...

P: n/a
Hello,

I am trying to create a map/dictionary where the type of key is known
ie std::string, but the value could be of any built in type. ie. int,
double etc. (something along the lines of map<string, Twhere T is
template argument)

To hold the value type I have something like:

template<class T>
struct Data
{
T value;
}

Now I am trying to declare a map as below:

std::map<std::string, Data>;

this doesn't/wouldn't work and I don't know how to declare it??

if I have a method which has to pass in this map as a parameter, how
would I do it??
e.g Foo(std::map<string, Dataparam ) doesn't work and I don't expect
it to either

Can someone please help!

Aug 10 '06 #1
Share this Question
Share on Google+
17 Replies


P: n/a
de*******@hotmail.com schrieb:
Hello,

I am trying to create a map/dictionary where the type of key is known
ie std::string, but the value could be of any built in type. ie. int,
double etc. (something along the lines of map<string, Twhere T is
template argument)

To hold the value type I have something like:

template<class T>
struct Data
{
T value;
}

Now I am trying to declare a map as below:

std::map<std::string, Data>;

this doesn't/wouldn't work and I don't know how to declare it??
If you want a heterogenous container, you need run-time polymorphism;
you can't do it with templates alone.

That is, use a virtual base class and templated sub-classes which hold
the actual type.

The easiest way would be to use either of boost::any or
boost::variant<>, they both do something similar:

std::map<std::string, boost::anymapOfAnyType;

--
Thomas
Aug 10 '06 #2

P: n/a
Many Thanks for your prompt reply! Can I please ask following

1) will boost::any let me store any type including built-in types and
are there good examples on their site with regards to this particular
feature?
2) when you said "That is, use a virtual base class and templated
sub-classes which hold the actual type." - did you mean declaring a
something like map<string, base*>? would the base have to be declared
as a template too?

Aug 10 '06 #3

P: n/a

de*******@hotmail.com wrote:
Hello,

I am trying to create a map/dictionary where the type of key is known
ie std::string, but the value could be of any built in type. ie. int,
double etc. (something along the lines of map<string, Twhere T is
template argument)

To hold the value type I have something like:

template<class T>
struct Data
{
T value;
}

Now I am trying to declare a map as below:

std::map<std::string, Data>;

this doesn't/wouldn't work and I don't know how to declare it??

if I have a method which has to pass in this map as a parameter, how
would I do it??
e.g Foo(std::map<string, Dataparam ) doesn't work and I don't expect
it to either

Can someone please help!
I think you can use

std::map<std::string, Data*>;

Aug 10 '06 #4

P: n/a
de*******@hotmail.com schrieb:
Many Thanks for your prompt reply! Can I please ask following

1) will boost::any let me store any type including built-in types and
are there good examples on their site with regards to this particular
feature?
There are some restrictions for the types documented, but you can store
all built-in types. For the examples, look for yourself:

http://www.boost.org/doc/html/any.html
2) when you said "That is, use a virtual base class and templated
sub-classes which hold the actual type." - did you mean declaring a
something like map<string, base*>? would the base have to be declared
as a template too?
Yes, I meant something like that, and no, the base class should better
not be a template. You can't put a templated class or pointer to
templated class in a container, you can do this only with a concrete
instantiation of the template. That is why you need a base class.

The boost::any class does this for you, and it works as a simple smart
pointer, so you don't even have to store raw pointers in the map.

--
Thomas
Aug 10 '06 #5

P: n/a
zh**********@gmail.com wrote:
de*******@hotmail.com wrote:
Hello,

I am trying to create a map/dictionary where the type of key is known
ie std::string, but the value could be of any built in type. ie. int,
double etc. (something along the lines of map<string, Twhere T is
template argument)
[...]
>
I think you can use

std::map<std::string, Data*>;
No. Data is not a type. It's a template. Any instantiation of the Data
template,
e.g. Data<int>, is a type. The arguments to the std::map template are
two
types. [1] Hence, you can write std::map<std::string, Data<int
MyMap;
With the proposed Data template that of course adds little value.

The better solution is already given. (Use boost)

HTH,
Michiel Salters

[1] Not counting the third argument, because it has a default
(std::allocator)

Aug 10 '06 #6

P: n/a
Looks like there is really no way in C++ to have a generic type like
that in a map. Templates solve half the problem but don't go all the
way.. :-(

it is not possible to use std::map<std::string, Data*for the reasons
mentioned by Michiel.
What I can do is make Data a base class, then derive templated class
from data and instantiate these, and store pointers to these in the
above map. All sounds like too much effort!
I like the idea of using boost but I am not allowed to use it in my
project :-(

Thanks to all of you again...

Aug 10 '06 #7

P: n/a
de*******@hotmail.com wrote:
Hello,

I am trying to create a map/dictionary where the type of key is known
ie std::string, but the value could be of any built in type. ie. int,
double etc. (something along the lines of map<string, Twhere T is
template argument)

To hold the value type I have something like:

template<class T>
struct Data
{
T value;
}

Now I am trying to declare a map as below:

std::map<std::string, Data>;

this doesn't/wouldn't work and I don't know how to declare it??

if I have a method which has to pass in this map as a parameter, how
would I do it??
e.g Foo(std::map<string, Dataparam ) doesn't work and I don't expect
it to either

Can someone please help!
Just to be clear: do you want to store actual values of different types
in the same map (if so, use boost::any as suggested by others), or are
you just wanting to have a "template typedef" that defines only one of
the existing tempalte parameters like this:

template<typename T>
struct MyMap
{
typedef std::map<std::string,Ttype;
};

MyMap<int>::type intMap;
MyMap<float>::type floatMap;

Cheers! --M

Aug 10 '06 #8

P: n/a
de*******@hotmail.com wrote:
[...] Templates solve half the problem but don't go all the
way.. :-(

[...] All sounds like too much effort!
Life... First you suffer through it, then you die...
Aug 10 '06 #9

P: n/a
Rather die than use VB or C# :-P

To the previous poster, no I did think of template typedef but that
only works if i want one specific type. I want a map which stores any
built in data type ie. int, double etc...
so something like map<string, object) in java or other similar
languages...

Victor Bazarov wrote:
de*******@hotmail.com wrote:
[...] Templates solve half the problem but don't go all the
way.. :-(

[...] All sounds like too much effort!

Life... First you suffer through it, then you die...
Aug 10 '06 #10

P: n/a
de*******@hotmail.com wrote:
I like the idea of using boost but I am not allowed to use it in my
project :-(
So go ahead and reinvent the wheel: write a discriminated union of your
own, and you'll acheive the same effect.

Cheers! --M

Aug 10 '06 #11

P: n/a
mlimber wrote:
de*******@hotmail.com wrote:
Rather die than use VB or C# :-P

To the previous poster, no I did think of template typedef but that
only works if i want one specific type. I want a map which stores any
built in data type ie. int, double etc...
so something like map<string, object) in java or other similar
languages...
I like the idea of using boost but I am not allowed to use it in my
project :-(

So go ahead and reinvent the wheel: write a discriminated union of your
own, and you'll acheive the same effect.

Cheers! --M
If you like the Java style, create an Object class and make subclasses
that will behave like wrappers of built-in data types (Integer, Bool,
etc.)

map<string,Object *will be your map type and you can use RTTI to
determine how to access the data

struct Object {
virtual ~Object() {} // allows delete by Object pointer
};

struct Integer: public Object { int data; Integer(int d): data(d) {}
};
struct Bool: public Object { bool data; Bool(bool d): data(d) {} };
....

of course a template can save you from the dirty work
template<typename T>
struct DataWrapper: public Object { T data; DataWrapper(T d): data(d)
};

....

map<string,Object *suckMap;
suckMap["integer"] = new Integer(10);
suckMap["a little bool"] = new Bool(false);
suckMap["other bool"] = new DataWrapper<bool>(false);
....
if( DataWrapper<long* t = dynamic_cast<DataWrapper<long>
>(suckMap["lonely long") ) {
cout << t->data << "is a long value" << endl;
}

Hope this helps

Diego Martins

Aug 11 '06 #12

P: n/a
Diego Martins wrote:
If you like the Java style, create an Object class and make subclasses
that will behave like wrappers of built-in data types (Integer, Bool,
etc.)
This is generally frowned upon. See the reasons why here:

http://www.research.att.com/~bs/bs_faq2.html#object

and

http://www.artima.com/intv/goldilocks2.html
>
map<string,Object *will be your map type and you can use RTTI to
determine how to access the data

struct Object {
virtual ~Object() {} // allows delete by Object pointer
};

struct Integer: public Object { int data; Integer(int d): data(d) {}
};
struct Bool: public Object { bool data; Bool(bool d): data(d) {} };
...

of course a template can save you from the dirty work
template<typename T>
struct DataWrapper: public Object { T data; DataWrapper(T d): data(d)
};

...

map<string,Object *suckMap;
suckMap["integer"] = new Integer(10);
suckMap["a little bool"] = new Bool(false);
suckMap["other bool"] = new DataWrapper<bool>(false);
...
if( DataWrapper<long* t = dynamic_cast<DataWrapper<long>
(suckMap["lonely long") ) {
cout << t->data << "is a long value" << endl;
}
Assuming you fix the syntax errors in this code, it will still not
likely do what you were attempting since std::map's bracket operator
will actually *insert* a default-initialized value (read: null pointer)
with the key "lonely long" if the key cannot be found in the map (cf.
footnote 3 here: http://www.sgi.com/tech/stl/Map.html#3).

This won't cause an immediate problem since dynamic_cast will either
succeed (if the map element with that key has a DataWrapper<long>* as
its value) or will return null and not enter the body of the
if-statement (because the type is different or because the pointer is
null). But the use of std::map<>::operator[]() could potentially insert
a null pointer, which the user of the map may not expect and which you
probably did not intend. This could be fixed by using
std::map<>::find() (or similar) to do the look-up instead.

Cheers! --M

Aug 11 '06 #13

P: n/a

mlimber wrote:
Diego Martins wrote:
If you like the Java style, create an Object class and make subclasses
that will behave like wrappers of built-in data types (Integer, Bool,
etc.)

This is generally frowned upon. See the reasons why here:

http://www.research.att.com/~bs/bs_faq2.html#object

and

http://www.artima.com/intv/goldilocks2.html

map<string,Object *will be your map type and you can use RTTI to
determine how to access the data

struct Object {
virtual ~Object() {} // allows delete by Object pointer
};

struct Integer: public Object { int data; Integer(int d): data(d) {}
};
struct Bool: public Object { bool data; Bool(bool d): data(d) {} };
...

of course a template can save you from the dirty work
template<typename T>
struct DataWrapper: public Object { T data; DataWrapper(T d): data(d)
};

...

map<string,Object *suckMap;
suckMap["integer"] = new Integer(10);
suckMap["a little bool"] = new Bool(false);
suckMap["other bool"] = new DataWrapper<bool>(false);
...
if( DataWrapper<long* t = dynamic_cast<DataWrapper<long>
>(suckMap["lonely long") ) {
cout << t->data << "is a long value" << endl;
}

Assuming you fix the syntax errors in this code, it will still not
likely do what you were attempting since std::map's bracket operator
will actually *insert* a default-initialized value (read: null pointer)
with the key "lonely long" if the key cannot be found in the map (cf.
footnote 3 here: http://www.sgi.com/tech/stl/Map.html#3).

This won't cause an immediate problem since dynamic_cast will either
succeed (if the map element with that key has a DataWrapper<long>* as
its value) or will return null and not enter the body of the
if-statement (because the type is different or because the pointer is
null). But the use of std::map<>::operator[]() could potentially insert
a null pointer, which the user of the map may not expect and which you
probably did not intend. This could be fixed by using
std::map<>::find() (or similar) to do the look-up instead.

Cheers! --M
thanks for the find() advice :-)

personally, I dislike this java-style. I only presented a possible
working solution for a "generic" container

# A "universal" class encourages sloppy thinking about types and
interfaces and leads to excess run-time checking.
# Using a universal base class implies cost: Objects must be
heap-allocated to be polymorphic; that implies memory and access cost.
Heap objects don't naturally support copy semantics. Heap objects don't
support simple scoped behavior (which complicates resource management).
A universal base class encourages use of dynamic_cast and other
run-time checking.

these issues are right, but what is the alternative if we really need a
generic container?

cya
Diego Martins

Aug 14 '06 #14

P: n/a
Diego Martins wrote:
mlimber wrote:
Diego Martins wrote:
If you like the Java style, create an Object class and make subclasses
that will behave like wrappers of built-in data types (Integer, Bool,
etc.)
This is generally frowned upon. See the reasons why here:

http://www.research.att.com/~bs/bs_faq2.html#object

and

http://www.artima.com/intv/goldilocks2.html

personally, I dislike this java-style. I only presented a possible
working solution for a "generic" container

# A "universal" class encourages sloppy thinking about types and
interfaces and leads to excess run-time checking.
# Using a universal base class implies cost: Objects must be
heap-allocated to be polymorphic; that implies memory and access cost.
Heap objects don't naturally support copy semantics. Heap objects don't
support simple scoped behavior (which complicates resource management).
A universal base class encourages use of dynamic_cast and other
run-time checking.

these issues are right, but what is the alternative if we really need a
generic container?
boost::any, of course. :-) See the previous posts in this thread.

Cheers! --M

Aug 14 '06 #15

P: n/a

mlimber wrote:
Diego Martins wrote:
mlimber wrote:
Diego Martins wrote:
If you like the Java style, create an Object class and make subclasses
that will behave like wrappers of built-in data types (Integer, Bool,
etc.)
>
This is generally frowned upon. See the reasons why here:
>
http://www.research.att.com/~bs/bs_faq2.html#object
>
and
>
http://www.artima.com/intv/goldilocks2.html
>
personally, I dislike this java-style. I only presented a possible
working solution for a "generic" container

# A "universal" class encourages sloppy thinking about types and
interfaces and leads to excess run-time checking.
# Using a universal base class implies cost: Objects must be
heap-allocated to be polymorphic; that implies memory and access cost.
Heap objects don't naturally support copy semantics. Heap objects don't
support simple scoped behavior (which complicates resource management).
A universal base class encourages use of dynamic_cast and other
run-time checking.

these issues are right, but what is the alternative if we really need a
generic container?

boost::any, of course. :-) See the previous posts in this thread.

Cheers! --M
sounds great! Can you explain to us how boost::any is implemented?

Diego Martins

Aug 15 '06 #16

P: n/a
Diego Martins wrote:
sounds great! Can you explain to us how boost::any is implemented?
Not here. Ask on the Boost Developer (or User) list, or look through
the code.

Cheers! --M

Aug 15 '06 #17

P: n/a

mlimber wrote:
Diego Martins wrote:
sounds great! Can you explain to us how boost::any is implemented?

Not here. Ask on the Boost Developer (or User) list, or look through
the code.

Cheers! --M
I can't figure out why some members of this great group take this
defensive posture.

Me and many users want to code in C++ and learn more C++ to write
better code in C++. This is the reason we spend time in usenet forums.

It is not bad to get a tool as a solution, but we must consider the
case when we aren't able to use external tools. Instead, many users do
prefer saying "BOOST AND GOOD BYE". This is not the first time I see
this things here :-(

This is not a helpdesk. This is a place where the users share their C++
experiencies. Why do ruin that?

Go rest and think about that

Diego Martins
HP

Aug 16 '06 #18

This discussion thread is closed

Replies have been disabled for this discussion.