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
CodePudding user response:
Well, my previous answer was completely wrong: as far as I can tell, your Hash
and Pred
are correct. However, the issue is somewhere else. operator ==
for std::unordered_multiset
uses std::is_permutation()
to perform comparison internally and doesn't provide any comparison function that algorithm, so default operator ==
for that type (in this case char*
) is used. There is UB due to that I think, but I don't really understand the phrasing there.
To be fair, this looks like an oversight in standard. operator ==
for std::unordered_multimap
doesn't allow comparing different types of maps, so it should be possible to pass Pred
instance to std::is_permutation
. Or maybe there is a reason to have it that way, but I don't see it.