I'm trying to understand how operator== gets considered for overload resolution in the following example in the standard library implementation for Clang or MSVC.
#include <string>
#include <string_view>
//#define WORKAROUND 1
namespace tst
{
template<class T>
class string_view
{
#if WORKAROUND
friend bool operator==( string_view a, string_view b);
#endif
};
template<class T, class A>
class string
{
public:
operator string_view<T>() const;
};
#if !WORKAROUND
template<class T>
bool operator==( string_view<T> a, string_view<T> b);
#endif
}
void foo()
{
tst::string<char, int> s1;
tst::string_view<char> sv;
if (s1 == sv) {}
if (sv == s1) {}
}
int main()
{
std::string s1;
std::string_view sv;
if (s1 == sv) {}
if (sv == s1) {}
return 0;
}
It compiles when WORKAROUND is defined as it is very well described here. However, looking into the sources of Clang and MSVC I don't see that this workaround is used by the library. The operator is defined outside of the class simply as:
template<class _CharT, class _Traits>
_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_INLINE_VISIBILITY
bool operator==(basic_string_view<_CharT, _Traits> __lhs,
basic_string_view<_CharT, _Traits> __rhs) _NOEXCEPT
{
if (__lhs.size() != __rhs.size()) return false;
return __lhs.compare(__rhs) == 0;
}
See github.
So my question is how does it work for STL?
If you look carefully in the libc++ code there is a workaround present in the code, just after the normal operator is defined there is a second version which is decorated with
__type_identity_t:Adding the C++20 equivalent
std::type_identityto your code resolves the problem:https://godbolt.org/z/86r6c8s1h
As explained in the post you linked to, conversions aren't considered when deducing template types,
std::type_identityworks around this problem.Cppreference does mention that this is necessary but not exactly how it should be implemented: