Gaetan
Gaetan

Reputation: 607

construct an unordered_map with value being a pair of string and object type

consider the following code:

namespace fruit {
    struct apple{
        ...
    };
}

namespace language{
    struct english{
        ...
    };
}

I want to do something like:

std::unordered_map<std::string, ? > mymap = { 
    {"paul", {"like", fruit::apple} },
    {"jonas", {"like", language::english} }
};

the key of my map is a string and the value should be such a pair <string, ? >.
What type should I give as value for my map? I think things like union or functor can be used to solve the problem, but how? thanks in advance.

Upvotes: 1

Views: 1794

Answers (4)

Gaetan
Gaetan

Reputation: 607

So I found a solution using std::type_index.

typedef std::pair<std::string, std::type_index> myPair;

std::unordered_map<std::string, myPair> myMap =
{
    {"paul", {"likes", std::type_index(typeid(fruit::apple))} },
    {"jonas",  {"likes", std::type_index(typeid(language::english))} }
};

thanks guys for your valuable suggestions.

Upvotes: 1

ObliteratedJillo
ObliteratedJillo

Reputation: 5166

Here's a snippet ( without the factory pattern => improve the syntax ) with proxy pattern so that you need not modify your existing objects:

struct base {
};

namespace fruit {
    struct apple {};
    struct apple_proxy: base {
        apple_proxy()
            :apple_ptr(make_shared<fruit::apple>())
        {}
        shared_ptr<apple> apple_ptr;
    };
}

namespace language {
    struct english {};
    struct english_proxy : base {
        english_proxy()
        :english_ptr(make_shared<language::english>())
        {}
        shared_ptr<english> english_ptr;
    };
}

int main() {
    std::unordered_map<std::string, shared_ptr<base>> map;

    shared_ptr<fruit::apple_proxy> a = make_shared<fruit::apple_proxy>();
    map.emplace(make_pair("apple",a));

    shared_ptr<language::english_proxy> e = make_shared<language::english_proxy>();
    map.emplace(make_pair("english", e));
}

Upvotes: 2

Slava
Slava

Reputation: 44248

If you cannot use std::variant or boost::variant this solution could work:

struct data {
    std::string action;
    std::unque_ptr<fruit::apple> apple;
    std::unque_ptr<language::english> english;

    data( std::string act, fruit::apple ap ) : 
        action( std::move( act ) ), 
        apple( std::make_unqiue<fruit::apple>( std::move( ap ) ) {}
    data( std::string act, language::english en ) : 
        action( std::move( act ) ), 
        english( std::make_unqiue<language::english>( std::move( en ) ) {}
};

but most probably your problem has better solution.

Upvotes: 0

Antua
Antua

Reputation: 185

This code compiles for me:

#include <unordered_map>
#include <utility>
#include <variant>

namespace fruit {
   struct apple{};
}

namespace language{
   struct english{};
}

int main(){
    std::unordered_map<std::string,std::pair<std::string,std::variant<fruit::apple, language::english> > > mymap { 
        {"paul", {"like", fruit::apple()} },
        {"jonas", {"like", language::english()}}
    };
}

Note that you may want to compile with something like -std=gnu++17.

Upvotes: 1

Related Questions