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

Discussion in 'C++' started by devmentee@hotmail.com, Aug 10, 2006.

  1. Guest

    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, T> where 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, Data> param ) doesn't work and I don't expect
    it to either

    Can someone please help!
    , Aug 10, 2006
    #1
    1. Advertising

  2. 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, T> where 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::any> mapOfAnyType;

    --
    Thomas
    Thomas J. Gritzan, Aug 10, 2006
    #2
    1. Advertising

  3. Guest

    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, 2006
    #3
  4. Guest

    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, T> where 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, Data> param ) 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, 2006
    #4
  5. 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
    Thomas J. Gritzan, Aug 10, 2006
    #5
  6. Guest

    wrote:
    > 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, T> where 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, 2006
    #6
  7. Guest

    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, 2006
    #7
  8. mlimber Guest

    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, T> where 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, Data> param ) 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,T> type;
    };

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

    Cheers! --M
    mlimber, Aug 10, 2006
    #8
  9. 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...
    Victor Bazarov, Aug 10, 2006
    #9
  10. Guest

    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:
    > 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, 2006
    #10
  11. mlimber Guest

    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
    mlimber, Aug 10, 2006
    #11
  12. mlimber wrote:
    > 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
    Diego Martins, Aug 11, 2006
    #12
  13. mlimber Guest

    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<>::eek:perator[]() 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
    mlimber, Aug 11, 2006
    #13
  14. 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<>::eek:perator[]() 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
    Diego Martins, Aug 14, 2006
    #14
  15. mlimber Guest

    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
    mlimber, Aug 14, 2006
    #15
  16. 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
    Diego Martins, Aug 15, 2006
    #16
  17. mlimber Guest

    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
    mlimber, Aug 15, 2006
    #17
  18. 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
    Diego Martins, Aug 16, 2006
    #18
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. RA Scheltema
    Replies:
    3
    Views:
    380
    RA Scheltema
    Jan 6, 2004
  2. Marijn
    Replies:
    5
    Views:
    439
    Marijn
    Feb 13, 2004
  3. Patrick Guio
    Replies:
    6
    Views:
    3,173
    chris
    Oct 20, 2004
  4. Replies:
    0
    Views:
    2,212
  5. albert kao
    Replies:
    12
    Views:
    578
    Roedy Green
    Oct 7, 2011
Loading...

Share This Page