Неоднозначная перегрузка для оператора '==' с собственным классом и std :: string_view

Я создал класс с именем MyClass в namespace N Теперь я определяю глобальный operator== в namespace N

namespace N
{
class MyClass
{
// member function begin()
// member function end()
// content omitted
}

template<typename T>
bool operator==(const MyClass& a_mc, const T& a_other)
{
    using namespace std;
    return std::equal(a_mc.begin(), a_mc.end(), begin(a_other));
}
}

Это приводит к тому, что другой код не может быть скомпилирован (включена-из-стека опущена):

ошибка: неоднозначная перегрузка для оператора '==' (типы операндов: 'std :: basic_string_view' и 'const char [3]')

примечание: кандидат: 'bool N :: operator == (const N :: MyClass &, const T &) [with T = char [3]]'

примечание: кандидат: 'constexpr bool std :: operator == (std :: basic_string_view <_CharT, _Traits>, std :: __ detail :: __ idt>) [с _CharT = char; _Traits = std :: char_traits; std :: __ detail :: __ idt> = std :: basic_string_view] '479 |
оператор == (basic_string_view <_CharT, _Traits> __x

Почему N::operator== даже считается?

-

Изменить первый код, который столкнулся с проблемой

bool N::MyClass::f(const std::string_view& a_thing)
{return a_thing.substr(0,2) == "XY";}

-

Минимальный рабочий пример:

#include <algorithm>
#include <string_view>
#include <type_traits>

namespace N
{
        struct MyClass
        {
                MyClass() noexcept = default;
                template<typename T,
                        typename = std::void_t<decltype(T{}.data())>,
                        typename = std::void_t<decltype(T{}.size())>>
                MyClass(const T& a_source)
                {}

                const char* begin() const { return 0; } // stub
                const char* end() const { return 0; } // stub
                bool f(const std::string_view& a_thing);
        };

        template<typename T>
        bool operator==(const MyClass& a_mc, const T& a_other)
        {
            using namespace std;
            return std::equal(a_mc.begin(), a_mc.end(), begin(a_other));
        }

        bool MyClass::f(const std::string_view& a_thing)
        {
                return a_thing.substr(0,2) == "XY";
        }
}

Компилировать с

g ++ -std = c ++ 17 example.cpp

Всего 1 ответ


MyClass имеет конструктор шаблонов, который работает с std::string_view .

Поскольку конструктор не помечен как explicit компилятору разрешено использовать его для неявных преобразований.

Это означает, что когда вы делаете

bool N::MyClass::f(const std::string_view& a_thing)
{return a_thing.substr(0,2) == "XY";}

компилятору разрешено преобразовывать a_thing.substr(0,2) в MyClass а затем его можно использовать для вызова вашего bool operator== .

Один из способов избежать подобных вещей - сделать конструктор MyClass явным.

template<typename T,
    typename = std::void_t<decltype(T{}.data())>,
    typename = std::void_t<decltype(T{}.size())>>
    explicit MyClass(const T& a_source)
    {}

Есть идеи?

10000