I'm trying to insert some pair value into a map. May map is composed by an object and a vector of another object. i don't know why but the only way to make the code to compile is to declare the first object like a pointer. But in this way when I insert some object, only the first pair is put into the map.
My map is this:
map<prmEdge,vector<prmNode> > archi;
this is the code:
{
bool prmPlanner::insert_edge(int from,int to,int h) {
prmEdge e;
int f=from;
int t=to;
if(to<from){
f=to;
t=from;
}
e.setFrom(f);
e.setTo(t);
vector<prmNode> app;
prmNode par=nodes[e.getFrom()];
prmNode arr=nodes[e.getTo()];
app.push_back(par);
app.push_back(arr);
archi.insert(pair<prmEdge,vector<prmNode> >(e,app) );
return true;
}
}
In this way, I have an error in compilation in the class pair.h.
What could I do?? Thank you very much.
You need to supply a comparator for prmEdge. My guess is that it uses the default comparator for map, e.g. comparing the address of the key -- which is always the same because e is local.
Objects that serve as Keys in the map need to be ordered, so you either need to supply a operator for comparing edges, or a comparator function for map.
class EdgeComparator {
public:
bool operator( )( const prmEdge& emp1, const prmEdge& emp2) const {
// ... ?
}
};
map<prmEdge,vector<prmNode>, EdgeComparator > archi;
The really hard part is deciding how to compare the edges so a definitive order is defined. Assuming that you only have from and to You can try with:
class EdgeComparator {
public:
bool operator( )( const prmEdge& emp1, const prmEdge& emp2) const {
if ( emp1.from != emp2.from )
return ( emp1.from < emp2.from );
return ( emp1.to < emp2.to );
}
};
It will sort on primary key from and secondary to.
The class prmEdge needs to define a comparison function (default is operator<) to work with std::map. Although you don't post that code, I would expect that to be your problem (for the record, pointer have an operator< defined.
struct A {
int a;
bool operator<(A other)
{
return a < other.a;
}
};
struct B {
int b;
};
bool cmp(B lhs, B rhs)
{
return lhs.b < rhs.b;
}
std::map<A, int> map_a;
std::map<B, int, std::pointer_to_binary_function<B, B, bool> > map_b(std::ptr_fun(cmp));
Map elements are ordered by their keys. But the map needs to know how:
Either overload the < operator in the prmEdge class...
class prmEdge
{
//...
public:
bool operator<(const prmEdge& right) const
{
//...
}
};
...or specify a comparator for the map:
class Comparator
{
public:
bool operator()(const prmEdge& left, const prmEdge& right) const
{
// ...
}
};
map<prmEdge, vector<prmNode>, Comparator> archi;
Related
Can I somehow use my own function for ordering the pairs in multimap? I have three classes CTimeStamp, CMail and CMailLog. And the thing is in the CMailLog I have
multimap<CTimeStamp, CMail> which I use because for this task I need solution which will be very fast for huge amounts of data and therefor I would need to somehow use method Compare from CTimeStamp when inserting into this multimap. The classes look something like this.
class CTimeStamp {
public:
int compare (const CTimeStamp &x) const;
...
}
class CMail {
...
}
class CMailLog {
public:
...
private:
multimap<CTimeStamp, CMail> logs;
}
I'm not sure how to do this or if it's even possible.
I would need to somehow use method Compare from CTimeStamp when inserting into this multimap
As from the std::multimap documentation, all you need is to either
provide a specialisation for std::less<CTimeStamp>
namespace std {
bool less<CTimeStamp>(const CTimeStamp& a, const CTimeStamp& b) {
return a.compare(b) < 0;
}
}
or
provide a custom comparator at the constructor:
CMailLog() :
logs([](const CTimeStamp& a, const CTimeStamp& b) { return a.compare(b) < 0; })
{}
I used a lambda expression in my last example for the constructor as I consider that's the shortest and most comprehensible form.
In fact any callable with the signature bool (const CTimeStamp&,const CTimeStamp&) would fit well.
You might also write a simple global function
bool foo(const CTimeStamp& a,const CTimeStamp& b) {
return a.compare(b) < 0;
}
or appropriate callable type
struct foo {
bool operator()(const CTimeStamp& a,const CTimeStamp& b) {
return a.compare(b) < 0;
}
};
and pass that one at the
multimap<CTimeStamp, CMail> logs;
in the constructor initializer list:
CMailLog() : logs(foo) {}
Callable struct version
CMailLog() : logs(foo()) {}
Hello I wanna know how to sort the map which Tkey variable is pointer type.
There is getName function which return char* type. so I tried to compare with strcmp. But there are some error in the return part.
struct Compare_P {
inline bool operator()(Person const& a, Person const& b) {
return (strcmp(a.getName(), b.getName())) < 0;
}
};
map<Person*, House*, Compare_P>A_List;
Your map's key is Person*, but the Compare_P::operator() takes Person const&. You can fix that by either defining
map<Person, House, Compare_P> A_List;
or by a correct Compare_P
struct Compare_P {
bool operator()(Person const* a, Person const* b) {
return (strcmp(a->getName(), b->getName())) < 0;
}
I have the following struct
struct MyClass {
int myInt;
std::map<int, int> myMap;
};
I want to use unordered_set<MyClass*, PointedObjHash, PointedObEq> but I can't find a valid way to declare PointedObEq.
I tried
struct PointedObjHash {
size_t operator() (MyClass* const& c) const {
std::size_t seed = 0;
boost::hash_combine(seed, c->myInt);
boost::hash_combine(seed, c->myMap);
return seed;
}
and I hope it is fine, but I can't find a way to declare PointedObjEq
--- EDIT ---
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
struct MyClass {
...
...
bool operator==(MyClass* const& c) {
return this->myInt == c->myInt & this->myMap == c->myMap;
}
If declare operator== inside the class debug never breaks, but I think 'cause MyClass == MyClass* never happens...
The unordered_set needs to use operator== (or PointedObjEq) to double-check the results of the hash function. The hash provides approximate equality, the equality function is used to weed out false positives.
If you've tested adding the same value to the set twice, then you've tested the equality function. To be sure, of course, you can have it print something to the console.
Since it's impossible to define an operator== function with two pointer operands, the PointedObjEq class will be necessary. Note that it takes a MyClass const * on both sides. Also, there's no need to use a reference to a pointer.
So,
struct PointedObjEq {
bool operator () ( MyClass const * lhs, MyClass const * rhs ) const {
return lhs->myInt == rhs->myInt
&& lhs->myMap == rhs->myMap;
}
};
This should do:
struct PointedObEq {
bool operator()(MyClass const * lhs, MyClass const * rhs) const {
return lhs->myInt == rhs->myInt && lhs->myMap == rhs->myMap;
}
};
The reason why your solution does not work is because you have effectively written a mechanism to compare a MyClass with a MyClass*, when you actually need something to compare a MyClass* with a MyClass*.
P.S.: My original answer passed the pointers by const&. Thinking about it, that's a strange coding style, so I changed it to pass the pointers by value.
typedef MyClass* PtrMyClass;
struct PointedObjCompare
{ // functor for operator==
bool operator()(const PtrMyClass& lhs, const PtrMyClass& rhs) const
{
// your code goes here
}
};
std::unordered_set < MyClass*, PointedObjHash, PointedObjCompare > myset;
Can a std::map's or std::unordered_map's key be shared with part of the value? Especially if the key is non-trivial, say like a std::string?
As a simple example let's take a Person object:
struct Person {
// lots of other values
std::string name;
}
std::unordered_map<std::string, std::shared_ptr<Person>> people;
void insertPerson(std::shared_ptr<Person>& p) {
people[p.name] = p;
// ^^^^^^
// copy of name string
}
std::shared_ptr<Person> lookupPerson(const std::string& name) const {
return people[name];
}
My first thought is a wrapper around the name that points to the person, but I cannot figure out how to do a lookup by name.
For your purpose, a std::map can be considered a std::set containing std::pair's which is ordered (and thus efficiently accessible) according to the first element of the pair.
This view is particularly useful if key and value elements are partly identical, because then you do not need to artificially separate value and key elements for a set (and neither you need to write wrappers around the values which select the key).
Instead, one only has to provide a custom ordering function which works on the set and extracts the relevant key part.
Following this idea, your example becomes
auto set_order = [](auto const& p, auto const& s) { return p->name < s->name; };
std::set<std::shared_ptr<Person>, decltype(set_order)> people(set_order);
void insertPerson(std::shared_ptr<Person>& p) {
people.insert(p);
}
As an alternative, here you could also drop the custom comparison and order the set by the addresses in the shared pointer (which supports < and thus can be used directly in the set):
std::set<std::shared_ptr<Person> > people;
void insertPerson(std::shared_ptr<Person>& p) {
people.insert(p);
}
Replace set by unordered_set where needed (in general you then also need to provide a suitable hash function).
EDIT: The lookup can be performed using std:lower_bound:
std::shared_ptr<Person> lookupPerson(std::string const& s)
{
auto comp = [](auto const& p, auto const& s) { return p->name < s; };
return *std::lower_bound(std::begin(people), std::end(people), s, comp);
}
DEMO.
EDIT 2: However, given this more-or-less ugly stuff, you can also follow the lines of your primary idea and use a small wrapper around the value as key, something like
struct PersonKey
{
PersonKey(std::shared_ptr<Person> const& p) : s(p->name) {}
PersonKey(std::string const& _s) : s(_s) {}
std::string s;
bool operator<(PersonKey const& rhs) const
{
return s < rhs.s;
}
};
Use it like (untested)
std::map<PersonKey, std::shared_ptr<Person> > m;
auto sptr = std::make_shared<Person>("Peter");
m[PersonKey(sptr)]=sptr;
Lookup is done through
m[PersonKey("Peter")];
Now I like this better than my first suggestion ;-)
Here's an alternative to davidhigh's answer.
struct Person {
// lots of other values
std::string name;
}
struct StrPtrCmp {
bool operator()(const std::string* a, const std::string* b) const {
return *a < *b;
}
}
std::map<const std::string*, std::shared_ptr<Person>, StrPtrCmp> people();
void insertPerson(std::shared_ptr<Person>& p) {
people[&(p.name)] = p;
}
std::shared_ptr<Person> lookupPerson(const std::string& name) const {
return people[&name];
}
And a few edits to make it work with std::unordered_map:
struct StrPtrHash {
size_t operator()(const std::string* p) const {
return std::hash<std::string>()(*p);
}
};
struct StrPtrEquality {
bool operator()(const std::string* a, const std::string* b) const {
return std::equal_to<std::string>()(*a, *b);
}
};
std::unordered_map<const std::string*, std::shared_ptr<Person>, StrPtrHash, StrPtrEquality> people();
I have following structure
enum quality { good = 0, bad, uncertain };
struct Value {
int time;
int value;
quality qual;
};
class MyClass {
public:
MyClass() {
InsertValues();
}
void InsertValues();
int GetLocationForTime(int time);
private:
vector<Value> valueContainer;
};
void MyClass::InsertValues() {
for(int num = 0; num < 5; num++) {
Value temp;
temp.time = num;
temp.value = num+1;
temp.qual = num % 2;
valueContainer.push_back(temp);
}
}
int MyClass::GetLocationForTime(int time)
{
// How to use lower bound here.
return 0;
}
In above code I have been thrown with lot of compile errors. I think I am doing wrong here I am new to STL programming and can you please correct me where is the error? Is there better to do this?
Thanks!
The predicate needs to take two parameters and return bool.
As your function is a member function it has the wrong signature.
In addition, you may need to be able to compare Value to int, Value to Value, int to Value and int to int using your functor.
struct CompareValueAndTime
{
bool operator()( const Value& v, int time ) const
{
return v.time < time;
}
bool operator()( const Value& v1, const Value& v2 ) const
{
return v1.time < v2.time;
}
bool operator()( int time1, int time2 ) const
{
return time1 < time2;
}
bool operator()( int time, const Value& v ) const
{
return time < v.time;
}
};
That is rather cumbersome, so let's reduce it:
struct CompareValueAndTime
{
int asTime( const Value& v ) const // or static
{
return v.time;
}
int asTime( int t ) const // or static
{
return t;
}
template< typename T1, typename T2 >
bool operator()( T1 const& t1, T2 const& t2 ) const
{
return asTime(t1) < asTime(t2);
}
};
then:
std::lower_bound(valueContainer.begin(), valueContainer.end(), time,
CompareValueAndTime() );
There are a couple of other errors too, e.g. no semicolon at the end of the class declaration, plus the fact that members of a class are private by default which makes your whole class private in this case. Did you miss a public: before the constructor?
Your function GetLocationForTime doesn't return a value. You need to take the result of lower_bound and subtract begin() from it. The function should also be const.
If the intention of this call is to insert here, then consider the fact that inserting in the middle of a vector is an O(N) operation and therefore vector may be the wrong collection type here.
Note that the lower_bound algorithm only works on pre-sorted collections. If you want to be able to look up on different members without continually resorting, you will want to create indexes on these fields, possibly using boost's multi_index
One error is that the fourth argument to lower_bound (compareValue in your code) cannot be a member function. It can be a functor or a free function. Making it a free function which is a friend of MyClass seems to be the simplest in your case. Also you are missing the return keyword.
class MyClass {
MyClass() { InsertValues(); }
void InsertValues();
int GetLocationForTime(int time);
friend bool compareValue(const Value& lhs, const Value& rhs)
{
return lhs.time < rhs.time;
}
Class keyword must start from lower c - class.
struct Value has wrong type qualtiy instead of quality
I dont see using namespace std to use STL types without it.
vector<value> - wrong type value instead of Value
Etc.
You have to check it first before posting here with such simple errors i think.
And main problem here that comparison function cant be member of class. Use it as free function:
bool compareValue(const Value lhs, const int time) {
return lhs.time < time ;
}
class is the keyword and not "Class":
class MyClass {
And its body should be followed by semicolon ;.
There can be other errors, but you may have to paste them in the question for further help.
You just want to make compareValue() a normal function. The way you have implemented it right now, you need an object of type MyClass around. The way std::lower_bound() will try to call it, it will just pass in two argument, no extra object. If you really want it the function to be a member, you can make it a static member.
That said, there is a performance penalty for using functions directly. You might want to have comparator type with an inline function call operator:
struct MyClassComparator {
bool operator()(MyClass const& m0, MyClass const& m1) const {
return m0.time < m1.time;
}
};
... and use MyClassComparator() as comparator.