I have a map of pair as key and bool as value. When i try to find a certain pair that is already included using map::find method, it's not finding any item. What do i do wrong?
I tried to implement a comparator class and set it as key_comp in map, but I'm not sure i did it right. Is this the solve?
I am working in VS12, I attached a photo with the debugging, you shall understand much more from that:
You are calling find with pair<char *, char*>(0x00ffc468, 0x00ffbdb0). There is no such pair in the set, so find returns end.
Your code compares char *'s, which checks if they point to the same place in memory, not whether they point to identical content. You should probably use std::string instead of char * rather than reinventing wheels.
Here's an example of a possible comparison function you could use if you insist on doing so:
bool less(
std::pair<char *, char *> const& p1,
std::pair<char *, char *> const& p2)
{
int i = strcmp (p1.first, p2.first);
if (i < 0)
return true;
if (i > 0)
return false;
return strcmp (p1.second, p2.second) < 0;
}
If you must use std:pair<char*, char*> as key in your map, you can use the following functor while creating the map.
struct MyCompare
{
bool operator()(std::pair<char const*, char const*> const& lhs,
std::pair<char const*, char const*> const& rhs)
{
int n1 = strcmp(lhs.first, rhs.first);
if ( n1 != 0 )
{
return n1 < 0;
}
return (strcmp(lhs.second, rhs.second) < 0);
}
};
typedef std::map<std::pair<char*,char*>, int, MyCompare> MyMap;
MyMap myMap;
Related
I am trying to create an unordered_map for <xml_node*,string> pair, where xml_node is an element of xml from pugixml library, and i wish to store its pointer as the key. I have declared the map like this :
unordered_map<xml_node*,string> label_hash;
Now the insert function is working well and good. But whenever I try to find an element from the hash like this :
string lb = string(label_hash.find(node));
I get the following error :
no matching function for call to ‘std::basic_string<char>::basic_string(std::_Hashtable<pugi::xml_node*, std::pair<pugi::xml_node* const, std::basic_string<char> >, std::allocator<std::pair<pugi::xml_node* const, std::basic_string<char> > >, std::_Select1st<std::pair<pugi::xml_node* const, std::basic_string<char> > >, std::equal_to<pugi::xml_node*>, std::hash<pugi::xml_node*>, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, false, false, true>::iterator)’|
Now do I need to implement a hash function and equal function for the map? I was trying to implement them like follows but it doesn't work :
struct hashing_func {
unsigned long operator()(const xml_node* key) const {
uintptr_t ad = (uintptr_t)key;
return (size_t)((13 * ad) ^ (ad >> 15));
//return hash<xml_node*>(key);
}
};
struct key_equal_fn {
bool operator()(const xml_node* t1, const xml_node* t2) const {
return (t1 == t2);
}
};
I am a bit new to C++ so a little help would be great!
Please read the documentation: unordered_map::find returns an iterator to pair<xml_node const*, string>. (You can't pass that to the string constructor.) Instead do this:
auto iterator = label_hash.find(node);
if (iterator != label_hash.end()) { // `.find()` returns `.end()` if the key is not in the map
string& lb = iterator->second; // The `&` is optional here, use it if you don't want to deepcopy the whole string.
// use lb
}
else {
// key not in the map
}
I wrote a little test program:
#include <unordered_map>
#include <string>
namespace pugi
{
struct xml_node {};
}
int main()
{
std::unordered_map<pugi::xml_node*, std::string> mymap;
pugi::xml_node n1;
mymap.emplace(&n1, "foo");
auto i = mymap.find(&n1);
i->second;
return 0;
}
This compiles perfectly, indicating that as, suspected, the problem is not with the use of a pointer as a map key, not a lack of custom comparitor and not the lack of a hash function.
unordered_map::find returns an iterator - which points to a key/value pair.
I'm trying to use a std::map where the keys are c-style strings rather than std::strings but am having problems getting it to compile on an IBM iSeries targetting v7r1m0
I'd like to use c-style strings because using the Performance Explorer (PEX) it appears that the creation of lots of temporary strings for the purpose of map lookups is very expensive.
To do this I have used a custom comparator but when compiling on the iSeries I get an error:
"/QIBM/include/t/xtree.t", line 457.30: CZP0218(30) The call does not
match any parameter list for "const mycompany::myapp::cmp_str::operator()".
"/QIBM/include/t/xtree.t", line 457.21: CZP1289(0) The implicit object
parameter of type "mycompany::myapp::cmp_str &" cannot be initialized with an
implied argument of type "const mycompany::myapp::cmp_str".
My comparator is defined as:
struct cmp_str
{
bool operator()(char const *a, char const *b)
{
return std::strcmp(a, b) < 0;
}
};
and used in a map :
class LocalSchema : public RecordSchema
{
public:
int Operation;
//map<string, int> FieldLookup;
map<char *, int, cmp_str> FieldLookup;
};
Am I doing something stupid?
EDIT:
changing to
std::map<char const*, int, cmp_str>
gives the same error. Looking in to the job log further I see that this error was produced while processing the following function:
inline int VxSubfile::IndexOfFieldInSchema(char * columnName)
{
std::map<char const*, int, cmp_str>::iterator iter = _fieldLookup.find(columnName);
if(iter == _fieldLookup.end())
{
return -1;
}
else{
jdebug("Returning index : %d", iter->second);
return iter->second;
}
}
Change
map<char *, int, cmp_str>
to
std::map<char const*, int, cmp_str>
that is, with std::, and with const.
Edit: Also make the comparison member function const, i.e.
struct cmp_str
{
bool operator()(char const *a, char const *b) const
{
return std::strcmp(a, b) < 0;
}
};
Note 1: IBM's C++ compilers are infamous for being non-conforming in subtle ways, so you may still run into problems.
Note 2: You need to ensure that the strings outlive the map. E.g. you can use a vector<unique_ptr<char const[]>> as owner for the strings, allowing you to clean up.
I have a mix of C and C++ files that collectively form my program. I am using boost unordered hash map which I initially defined as:
typedef boost::unordered_map<char *, int> my_map;
However, the map was acting weird; find(key) could not find keys that actually existed in the hash map. I, then, changed the definition to:
typedef boost::unordered_map<std::string, int> my_map;
and now the hash map works fine. Nevertheless, it is inconvenient for me to convert my char * to std::string in order to use the map. Is there a way to make the first definition work?
std::unordered_map
Oh aha. Noticed you wanted unordered_map. One of my favourites is to use boost::string_ref to represent strings without copying, so you could do
std::unordered_map<boost::string_ref, int> map;
with a quick & dirty hash implementation like:
namespace std
{
template<>
struct hash<boost::string_ref> {
size_t operator()(boost::string_ref const& sr) const {
return boost::hash_range(sr.begin(), sr.end());
}
};
}
See it Live On Coliru
std::map
You can use a custom comparator:
std::map<char const*, int, std::less<std::string> > map;
Note that this is highly inefficient, but it shows the way.
More efficient would be to wrap/use strcmp:
#include <cstring>
struct less_sz
{
bool operator()(const char* a, const char* b) const
{
if (!(a && b))
return a < b;
else
return strcmp(a, b) < 0;
}
};
And then
std::map<char const*, int, less_sz> map;
See it Live On Coliru
I have a problem with std::map.
I'm using it to map some list of pairs under a specific index:
map<string, list<pair<string, int> > > List;
It's used in Dijkstra algorithm.
The main problem is that map sorts string keys in alphabetical order, like this:
AAA, AA0, AA1, AAB, AC1 = AA0->AA1->AAA->AAB->AC1
But I would like to sort it in a different way:
AAA, AA0, AA1, AAB, AC1 = AAA->AAB->AA0->AA1->AC1
Is there any solution to this? I read about making my own comparing class, but I have no idea how to do this. Or maybe there's some other way to solve it?
You have to provide your own comparison functor, which must be passed as 3rd template parameter when instantiating the map. For example:
struct Comp
{
bool operator()(const std::string& lhs, const std::string& rhs) const
{
// implement your comparison logic here
}
};
Instances of this class is callable (hence "functor") with two string parameters, and should return true or false based in a strict weak ordering logic.
Then instantiate the map using the functor type:
std::map<string, list<pair<string, int>>, Comp> List;
Now the map will use your comparison logic internally to define the ordering of its elements.
Like others have said, you need to implement a custom comparer...
struct custom_comparer
{
bool operator()(const std::string& left, const std::string& right) const
{
return std::lexicographical_compare(
left.cbegin(), left.cend(),
right.cbegin(), right.cend(),
[](char l, char r) -> bool
{
bool ldigit = isdigit(l) != 0,
rdigit = isdigit(r) != 0;
return (!ldigit && rdigit) || (ldigit == rdigit && l < r);
});
}
};
And use it...
std::map<string, list<pair<string, int>>, custom_comparer> List;
Normal string comparison operators use lexicographical_compare. My custom_comparer above also uses it, but with a custom comparer plugged in. The custom comparer uses isdigit to do the comparison you want.
You have to write your own comparer:
struct custom_string_comparer
{
bool operator()(const std::string& s1, const std::string& s2)
{
return ...; // your comparison here
}
};
map<string, list<pair<string, int>>, custom_string_comparer> List;
Yes. You need to supply a third template argument, see the docs.
struct HASH_CMP {
bool operator()(vector<int> V, vector<int> W) const {
for(int i = 0; i < 10; i++)
if(V[i] != W[i]) return false;
return true;
}
};
hash_map< std::vector<int>, int, HASH_CMP > H;
long long inHash(const vector<int> &V) {
if(H.find(V) == H.end()) return -1; //this line
return H[V];
}
I have declared the following hash, given the comparing class above and I receive an error at the line mentioned saying:
no match for call to '(const HASH_CMP) (const std::vector<int, std::allocator<int> >&)
I need some help on fixing this code.
The third template argument is the hash functor. The comparison functor is the fourth template argument. Thus you need:
hash_map<std::vector<int>, int, HASH_HASH, HASH_CMP>
And you still need to write HASH_HASH.
(I recommend you look at Boost's hash_range implementation for inspiration.) Also note that equality for vectors is already defined (and more efficiently than your version) and shouldn't require self-written code.
As the error is telling you, you need a hashing function that takes a const std::vector<int>& and returns a size_t. To put something in a hash map, there has to be some way to hash it.
This will work:
size_t operator()(const vector<int>& vec)
{
size_t v = 0;
for (vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it)
v = (v ^ *it) * 0x9e3779b9;
return v;
}