using custom classes with unordered_map in cpp
Why would you want to convert the time to string first? Your goal should be a wide spreading of hash values with an inexpensive hash function, right? Also this is real time? In which case you get away with unsigned short
for the members.
#include <unordered_map>
#include <functional>
#include <string>
#include <iostream>
class Time {
public:
Time(unsigned short h = 0, unsigned short m = 0, unsigned short s = 0) :
hours(h), minutes(m), seconds(s) {}
bool operator==(Time const& other) const {
return (seconds==other.seconds &&
minutes==other.minutes &&
hours==other.hours);
}
unsigned short hours, minutes, seconds;
};
std::ostream& operator<<(std::ostream& o, Time const& t) {
o << t.hours << ":" << t.minutes << ":" << t.seconds;
return o;
}
namespace std {
template<> struct hash<Time> {
size_t operator()(Time const& t) const {
return size_t(((t.seconds * 37 + t.minutes) * 37 + t.hours) * 37);
}
};
}
int main() {
std::unordered_map<Time, std::string> u;
u[Time(3,15,31)] = std::string("Hello world");
u[Time(3,15,32)] = std::string("foo");
u[Time(3,15,32)] = std::string("bar");
for (auto const& i : u) {
std::cout << i.first << " - " << i.second << std::endl;
}
return 0;
}
unordered_map for custom class does not cause error when inserting the same key
Your hash
and operator ==
must satisfy a consistency requirement that they currently violate. When two objects are equal according to ==
, their hash codes must be equal according to hash
. In other words, while non-equal objects may have the same hash code, equal objects must have the same hash code:
size_t operator()(const Line& k) const {
return hash<float>()(k.getM());
}
Since you compare only one component for equality, and ignore the other component, you need to change your hash function to use the same component that you use to decide the equality.
Unordered_map with custom class as key
emplace(d->get_name()->get_str(), d);
Here you try to construct a std::unordered_map<Symbol, Decl*>::value_type
(i.e. a std::pair<Symbol, Decl*>
) from a const std::string&
and a Decl*
.
The problem is that Symbol
has no constructor taking a std::string
, only a std::string const*
.
This is the line in the error messages that gives the hint:
/Library/Developer/CommandLineTools/usr/include/c++/v1/utility:422:5: note: candidate constructor not viable: no known conversion from
'std::__1::basic_string<char>' to 'const const Symbol' for 1st argument
pair(_T1 const& __t1, _T2 const& __t2)
Custom structure as key in unordered_map
You need to const
-qualify ItemHash::operator()(Item)
, i.e.,
struct ItemHash {
size_t operator()(Item item) const
// ^^^^ here
{
// as before...
}
Note that as @JeJo pointed out in the comments, you need the same fix for ItemEqual
.
Custom class pointer as unordered map key
I tried your code and found 3 problems:
- Declaration of map: it should read
std::unordered_map<MyClass*, int>
- call of undefined functions (
tt1->find
/tt1->end
, should readtt1->testMap.XXX
) - Call of
make_pair
doesn't require template arguments. The compiler will infer them. This actually causes a problem, as the compiler tries to callmake_pair(MyClass *&&, int &&)
. If I omit the template arguments, it works (make_pair(mc1, 10)
)
As for point 3:
make_pair is declared as follows in C++11 (C++14 just adds constexpr
) (cppreference):
template< class T1, class T2 >
std::pair<V1,V2> make_pair( T1&& t, T2&& u );
For template argument deduction, the follwing rule applies (cf. cppreference)
4) If P is an rvalue reference to a cv-unqualified template parameter (so-called "forwarding reference"), and the corresponding function call argument is an lvalue, the type lvalue reference to A is used in place of A for deduction (Note: this is the basis for the action of std::forward)
(emphasis mine)
So the compiler will infer:
std::make_pair<MyClass *&, int>(MyClass *&, int &&);
where MyClass *&
can bind to your actual argument.
If you directly specify the template types, the compiler will stick to
std::make_pair<MyClass *, int>(MyClass *&&, int &&).
As your argument is a lvalue, it cannot be converted to a rvalue-reference, and compilation fails
Related Topics
Correct Way of Passing Pointer to Another Thread
C++: How to Iterate Over Each Char in a String
How Come a Non-Const Reference Cannot Bind to a Temporary Object
Vector Converted All Negative Values to Zero
How to Install (V142) Build Tools in Visual Studio
Most Efficient Way of Copying a Raw Byte Array into an Empty Byte Vector
Escape Sequence \F - Form Feed - What Exactly Is It
Define Preprocessor Macro Through Cmake
Visual Studio Code: Take Input from User
How to Print Current Time (With Milliseconds) Using C++/C++11
Most Efficient Way to Compare a Variable to Multiple Values
How to Fully Disable Resizing a Window Including the Resize Icon When the Mouse Hovers the Border
Countdown Until Matching Digits
Forcing the Qt Gui to Update Before Entering a Separate Function