Is this a bug, or am I doing something wrong? I already tried providing hashing and equality functors for the pointer type, but it doesn't seem to work. I even tried creating my own miniature template container just to test the functors.
Hashing functor:
class CharPtHash
{
private:
using pChar = char*;
public:
size_t operator()(const pChar& c) const
{
std::hash<char> hasher;
if (c == nullptr)
{
return 0;
}
return hasher(*c);
}
};
Equality:
class CharPtEqual
{
private:
using pChar = char*;
public:
bool operator()(const pChar& lhs, const pChar& rhs)const
{
if (lhs == rhs)//not sure of nullptr is equal to itself.
{
return true;
}
else if (lhs==nullptr || rhs==nullptr)
{
return false;
}
return *lhs == *rhs;
}
};
Main:
int main()
{
cout << "Testing unordered_multiset with keys being simple types:\n";
unordered_multiset<char> sA1({ 'a','b','c' });
unordered_multiset<char> sA2({ 'a','c','b' });
cout << "Values: " << endl << sA1 << endl << sA2 << endl;
cout << (sA1 == sA2 ? "Equal" : "Not Equal");
cout << endl;
cout << "Testing unordered_multiset with keys being pointers to simple types:\n";
char** c1 = new char* [3]{ new char('a'), new char('b'), new char('c') };
char** c2 = new char* [3]{ new char('a'), new char('c'), new char('b') };
unordered_multiset<char*,CharPtHash,CharPtEqual> sB1;
unordered_multiset<char*,CharPtHash,CharPtEqual> sB2;
sB1.insert(c1[0]);
sB1.insert(c1[1]);
sB1.insert(c1[2]);
sB2.insert(c2[0]);
sB2.insert(c2[1]);
sB2.insert(c2[2]);
cout << "Values: " << endl << sB1 << endl << sB2 << endl;
cout << (sB1 == sB2 ? "Equal" : "Not Equal");
cout << endl;
cin.get();
}
I tried compiling it to c++20 and c++14 using Visual Studio 2022.
This is the output:
Testing unordered_multiset with keys being simple types:
Values:
{ a, b, c }
{ a, c, b }
Equal
Testing unordered_multiset with keys being pointers to simple types:
Values:
{ a, b, c }
{ a, c, b }
Not Equal
Supplying your own KeyEqual
only change the behavior internally, i.e. inserting new items. However it has no effects on operator==
.
According to operator==
(std::unordered_multiset
), the behavior of it is as if each equivalent equal_range
s were compared with std::is_permutation
.
You can potentially specialize the behavior of std::is_permutation
for your set pre-C++20(this is undefined behavior since C++20):
template<>
bool std::is_permutation(
std::unordered_multiset<char*, CharPtHash, CharPtEqual>::const_iterator l_begin,
std::unordered_multiset<char*, CharPtHash, CharPtEqual>::const_iterator l_end,
std::unordered_multiset<char*, CharPtHash, CharPtEqual>::const_iterator r_begin)
{
return std::is_permutation(l_begin, l_end, r_begin, CharPtEqual{});
}
Or just create your own char*
wrapper with a custom operator==
.