Java hashmap.get() in c++ - c++

In java you could have something like:
Map<Foo, List<Bar>> things;
for(Foo foo : things.getKeySet()){
List<bar> = things.get(foo);
}
Is there an equivalent for c++, maybe in std::map? Thanks for any help.

See std::map and std::vector (ArrayList) and maybe std::unordered_map (HashMap) and std::list (LinkedList)
For example:
#include <map>
#include <vector>
struct Foo {};
struct Bar {};
int main()
{
std::map<Foo, std::vector<Bar>> things;
for(auto& thing: things) {
const Foo& foo = thing.first; // key
std::vector<Bar>& bars = thing.second; // value
// use foo & bars here
}
}
Note: A std::map requires that a comparison operator be defined for user defined types like Foo:
struct Foo
{
int i = 0;
Foo(int i): i(i) {}
// need a comparison operator for ordered containers
bool operator<(const Foo& foo) const { return i < foo.i; }
};

Related

Index retrieval as a function of the boost::multi_index::sequenced<> offset

I am in a situation where I am forced to use a std::vector container as my underlying data structure. I'm trying to exploit boost::multi_index::sequenced<> to shadow the vector offset, and provide a mechanism for richer data queries. I really don't want to unnecessarily copy all the data from one container to another.
In the example code snippet below I have a class BarInterface that manages the insertion and removal of elements to the Bar::foos container. Initially I tried to store references to the vector elements as elements of the typedef boost::multi_index_container, but these are not stable against insertions.
What I'd like to do is have a custom key extractor that is a function of the _bar container and the boost::multi_index::sequenced<> index. So, for example to get the name of an element, I'd find the sequence offset x, and then _bar.foos[x].name. So, I'm really just using boost::multi_index as a proxy for richer queries against a vector of variable size.
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface {
public:
struct Dummy {};
BarInterface(Bar& bar) : _bar(bar) {
for (auto& foo : bar.foos) {
_idx.get<1>().insert(Dummy{});
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
// I need something here that takes the boost::multi_index::sequenced<>
// key to get the offset x, and then returns this->_bar.foos[x].name!
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(Dummy{});
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
protected:
Bar& _bar;
MultiIndex _idx;
};
I know that boost::multi_index supports all sorts of key extractors -- for member variables, member functions, global function, etc. However, I can't seem to find an example showing how to generate a key as a function of a boost::multi_index::sequenced<> index. Is this possible, or is there an elegant alternative?
This is extremely brittle and I wouldn't recommend going to production with such code, but since you asked for it:
Live Coliru Demo
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <iostream>
#include <string>
#include <vector>
struct Foo {
std::string name;
};
struct Bar {
std::vector<Foo> foos;
};
class BarInterface;
struct Dummy
{
Dummy(const Foo& x): p(&x){}
Dummy(const Dummy&): p(nullptr){}
const Foo* p;
};
struct NameExtractor
{
NameExtractor(BarInterface* p): p(p){}
using result_type=std::string;
const result_type& operator()(const Dummy& d)const;
BarInterface* p;
};
class BarInterface {
public:
BarInterface(Bar& bar) :
_idx(boost::make_tuple(
boost::tuple<>(),
boost::make_tuple(NameExtractor(this), std::less<std::string>())
)),
_bar(bar)
{
for (auto& foo : bar.foos) {
_idx.get<1>().insert(bar.foos.back());
}
}
// Index
struct Name {};
typedef boost::multi_index_container<
Dummy, // We're not actually storing anything here
boost::multi_index::indexed_by<
boost::multi_index::random_access<>, // Kept inline with vector order!
boost::multi_index::ordered_unique<
boost::multi_index::tag<Name>,
NameExtractor
>
>
> MultiIndex;
// Insert
void insert(const Foo& foo) {
_bar.foos.push_back(foo);
_idx.get<1>().insert(_bar.foos.back());
}
// Remove
template <typename T>
void remove(T it) {
_bar.foos.erase(_bar.foos.begin() + std::distance(_idx.begin(), _idx.project<0>(it)));
_idx.erase(_idx.project<0>(it));
}
void remove(const char* name) {
remove(_idx.get<1>().find(name));
}
void print()const
{
auto key=_idx.get<1>().key_extractor();
for(const auto& d: _idx.get<1>()){
std::cout<<key(d)<<" ";
}
std::cout<<"\n";
}
protected:
friend NameExtractor;
Bar& _bar;
MultiIndex _idx;
};
const NameExtractor::result_type& NameExtractor::operator()(const Dummy& d)const
{
if(d.p){
return d.p->name;
}
else{
std::size_t offset=p->_idx.iterator_to(d)-p->_idx.begin();
return p->_bar.foos[offset].name;
}
}
int main()
{
Bar bar;
BarInterface bi(bar);
bi.insert(Foo{"hello"});
bi.insert(Foo{"bye"});
bi.insert(Foo{"Boost"});
bi.print();
bi.remove("bye");
bi.print();
bi.insert(Foo{"MultiIndex"});
bi.print();
}
Output
Boost bye hello
Boost hello
Boost MultiIndex hello

How to move the contents of TArray

In C++ I can do
class A
{
public:
A(std::vector<std::unique_ptr<int>> v) : _v(std::move(v)) {}
private:
std::vector<std::unique_ptr<int>> _v;
}
How can I achieve something similar with ue4 types (TArray, TUniquePtr), i.e. how to move the contents of TArray?
Complete example:
#include <cassert>
#include <memory>
#include <vector>
class MyObj {};
class A {
public:
A(std::vector<std::unique_ptr<MyObj>> v) : _v(std::move(v)) {}
auto GetV() { return _v.front().get(); }
private:
std::vector<std::unique_ptr<MyObj>> _v;
};
int main() {
auto v = std::vector<std::unique_ptr<MyObj>>();
v.push_back(std::make_unique<MyObj>());
A a(std::move(v));
assert(a.GetV());
}
TArray has a move constructor (i.e., a constructor whose signature is TArray(TArray &&other)) as can be seen here.
So std::move should work on TArray the same way as it does on std::vector.
To complete the answer of Brennan:
C++ std -> UE4 equivalent:
std::vector -> TArray
std::unique_ptr -> TUniquePtr
std::make_unique -> MakeUnique
std::move -> MoveTempIfPossible (use MoveTemp to get compile time checks for rvalues and const)
So the code example from above with native UE4 classes would look like
class MyObj {};
class A {
public:
A(TArray<TUniquePtr<MyObj>> v) : _v(MoveTemp(v)) {}
auto GetV() { return _v[0].Get(); }
private:
TArray<TUniquePtr<MyObj>> _v;
};
int main() {
auto o = MyObj{};
auto v = TArray<TUniquePtr<MyObj>>();
v.Add(MakeUnique<MyObj>(o));
A a(MoveTemp(v));
assert(a.GetV());
}

std::hash for unique ptr in unordered map

I'm trying to hold a polymorphic type as a key in a map.
I came up with the following two structures:
Note that Game is an abstract class and the data structure I use is :
std::unordered_map<gamePtr,int> _allGames;
while gamePtr is a typedef for:
unique_ptr<Game>
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(std::unique_ptr<Game> game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}
};
struct cmp_games {
bool operator() (std::unique_ptr<Game> game1, std::unique_ptr<Game> game2) const {
return *game1 == *game2;
}
};
The cmp_games comparator seems to work fine but the std::hash does not because it tries to copy a unique_ptr (Which is ofc impossible) and I've no idea how to get over it.
Would love to hear some suggestions (If that is even possible).
EDIT: The comparator also doesn't seem to work properly. how do I make this map work correctly with unique_ptr as a key?
EDIT2:
Came up with:
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const {
return (std::hash<string>()(std::to_string(game->firstTeamFinalScore()) + game->firstTeam() + game->secondTeam()));
}
};
template<>
struct std::equal_to<std::unique_ptr<Game>> {
bool operator() (const std::unique_ptr<Game>& game1,const std::unique_ptr<Game>& game2) const {
return *game1 == *game2;
}
};
Should they be enough?
The standard provides a specilization so that std::hash<unique_ptr<T>> is the same as std::hash<T*>. So provide a specialization for std::hash<Game *>. For example:
#include <iostream>
#include <memory>
#include <unordered_map>
#include <cstdlib>
struct foo
{
foo(unsigned i) : i(i) {}
unsigned i;
};
namespace std {
template<>
struct hash<foo *>
{
size_t operator()(foo const *f) const
{
std::cout << "Hashing foo: " << f->i << '\n';
return f->i;;
}
};
}
int main()
{
std::unordered_map<std::unique_ptr<foo>, int> m;
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(10)), 100));
m.insert(std::make_pair(std::unique_ptr<foo>(new foo(20)), 200));
}
Live demo
Another option is to change your existing std::hash specialization so that it takes the unique_ptr by reference.
size_t operator()(std::unique_ptr<Game> const& game) const
// ^^^^^^ no more copying
EDIT: std::unique_ptr provides comparison operators that compare the managed pointers. If you want the unordered_map to test the Game objects themselves for equality, provide an operator== overload instead of specializing std::equal_to
inline bool operator==(const std::unique_ptr<Game>& game1,
const std::unique_ptr<Game>& game2)
{
return *game1 == *game2;
}
This, in turn, requires that you've provided an equality operator for Game (or you could just add the logic to the function above).
inline bool operator==(Game const& game1, Game const& game2)
{
return // however you want to compare these
}
Pass the game by const reference into std::hash::operator():
template<>
struct std::hash<std::unique_ptr<Game>> {
size_t operator()(const std::unique_ptr<Game>& game) const;
}
The same applies to cmp_games::operator().

How to insert into STL set?

I'm having problems and I'm not sure I understand the STL documentation. Let's say I have this:
#include <set>
...
struct foo
{
int bar;
};
struct comp
{
inline bool operator()(const foo& left,const foo& right)
{
return left.bar < right.bar;
}
};
int main()
{
std::set<foo,comp> fooset; // Uses comparison struct/class object comp to sort the container
...
return 0;
}
How do I insert struct foos into the set using my own comparator struct?
You can use the set::insert method, there is nothing more to do. For example,
foo f1, f2;
f1.bar = 10;
f2.bar = 20;
fooset.insert(f1);
fooset.insert(f2);

C++ member template for boost ptr_vector

I'm trying to write a container class using boost::ptr_vector. Inside the ptr_vector I would like to include different classes. I'm trying to achieve that using static templates, but so far I'm not able to do that. For example, the container class is
class model {
private:
boost::ptr_vector<elem_type> elements;
public:
void insert_element(elem_type *a) {
element_list.push_back(a);
}
};
and what I'm trying to achieve is be able to use different elem_type classes. The code below doesn't satisfy my requirements:
template <typename T>class model {
private:
boost::ptr_vector<T> elements;
public:
void insert_element(T *a) {
element_list.push_back(a);
}
};
because when I initialize the container class I can only use one class as template:
model <elem_type_1> model_thing;
model_thing.insert_element(new elem_type_1)
but not elem_type_2:
model_thing.insert_element(new elem_type_2)//error, of course
It is possible to do something like using templates only on the member?
class model {
private:
template <typename T> boost::ptr_vector<T> elements;
public:
void insert_element(T *a) {
element_list.push_back(a);
}
}; //wrong
So I can call the insert_element on the specific class that I want to insert? Note that I do not want to use virtual members.
Thanks!
Try using a vector of boost::variant:
#include <iostream>
#include <vector>
#include <boost/variant.hpp>
#include <boost/foreach.hpp>
struct Foo
{
Foo(int v=0) : a(v) {}
int a;
};
struct Bar
{
Bar(int v=0) : b(v) {}
int b;
};
struct print_visitor : public boost::static_visitor<>
{
void operator()(const Foo& foo) const
{
std::cout << "Foo " << foo.a << "\n";
}
void operator()(const Bar& bar) const
{
std::cout << "Bar " << bar.b << "\n";
}
};
int main()
{
typedef boost::variant<Foo, Bar> Variant;
std::vector<Variant> bag;
bag.push_back(Foo(123));
bag.push_back(Bar(456));
BOOST_FOREACH(const Variant& element, bag)
{
boost::apply_visitor(print_visitor(), element);
}
}
boost::variant's apply_visitor functions are useful for avoiding excessive casting back to the original type.
Vector is contains elements where each element has the same type as others. If you want to create vector of elements of different classes you could use vector of elements of type boost::any.