Skip to content

<xhash>: Some member functions of transparent hash containers fail to work with initializer lists #5207

@frederick-vs-ja

Description

@frederick-vs-ja

Describe the bug

From DevCom-10819520.

The following program don't compile with MSVC STL.

#include <unordered_map>
#include <unordered_set>

struct elem { 
    elem(unsigned val) : value(val) {}
    unsigned value = 0;
};
struct hash {
    using is_transparent = void;
    unsigned operator()(elem e) const { return e.value; }
};
struct equal {
    using is_transparent = void;
    unsigned operator()(elem e1, elem e2) const { return e1.value == e2.value; }
};

int main() {
    std::unordered_map<elem, int, hash, equal> map;
    (void)map.find(1u);   // OK
    (void)map.find({1u}); // MSVC: compile error, GCC: OK
    std::unordered_set<elem, hash, equal> set;
    (void)set.find(1u);   // OK
    (void)set.find({1u}); // MSVC: compile error, GCC: OK
}

Command-line test case

Godbolt link

Expected behavior

The program compiles. No "reference to cv void" is attempted to formed.

I think this bug is due to wrong _Deduce_key type.

STL/stl/inc/xhash

Lines 108 to 121 in 9082000

#if _HAS_CXX20
template <class _Kty, class _Hasher, class _Keyeq>
requires _Is_transparent_v<_Hasher> && _Is_transparent_v<_Keyeq>
struct _Uhash_choose_transparency<_Kty, _Hasher, _Keyeq> {
// transparency selector for transparent hashed containers
template <class _Keyty>
using _Deduce_key = const _Keyty&;
template <class _Container, class _Kx>
static constexpr bool _Supports_transparency =
!disjunction_v<is_convertible<_Kx, typename _Container::const_iterator>,
is_convertible<_Kx, typename _Container::iterator>>;
};
#endif // _HAS_CXX20

When brace initializer list is used as argument, the implementation should (as-if) fallback to the non-transparent overloads. But the wrong const void& type is attempted to be formed now.

STL version

All existing versions since VS 2019 16.5 (which got WG21-P1690R1 implemented).

Additional context

BTW, MSVC STL currently accepts the following bogus program even before C++20 (Godbolt link).

#include <unordered_set>

int main()
{
    std::unordered_set<int> m{1, 2, 3};
    auto it = m.find<void()>(1);
    return it == m.end();
}

Although this may still be conforming due to [member.functions]/2.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfixedSomething works now, yay!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions