Как написать оператор == для работы с неявно литыми/построенными типами

Почему это не работает, поскольку есть возможность "конструировать" неявно?

class A {};

template<typename T>
class Type {

public:
    Type() = default;
    Type(T* ptr) {
    }
};

template<typename T>
bool operator==(Type<T> l, Type<T> r) {
    return true;
}

int main() {
    A a;
    Type<A> type(&a);
    bool v = (type == &a); // Does not work
    //bool v = (type == Type<A>(&a)); // That would work
}

Почему неявная конструкция Type<A> с (&base, которая является A*) не используется? Как я могу написать этот код, чтобы он работал?

Ответ 1

Определяемые пользователем преобразования не учитываются при проверке работоспособности шаблона функции.

При проверке шаблона функции для жизнеспособности реализация пытается вывести параметры шаблона в соответствии с правилами вывода параметров шаблона. Эти правила не включают преобразования типов (только настройки типа, такие как удаление квалификаторов и ссылок). Если вычет заканчивается, кандидат отклоняется.

В вашем случае T не может быть выведено из Type<A> и A. Вам нужно, чтобы оба аргумента имели один и тот же тип Type<X> для успешного выполнения вывода.

Ответ 2

Вы можете заставить оператора перегружать функцию друга внутри вашего класса Type следующим образом:

template<typename T>
class Type {

public:
    Type() = default;
    Type(T* ptr) {
    }

    inline friend bool operator==(Type<T> l, Type<T> r) {
        return true;
    }
};

Это гарантирует, что оператор фактически создается с момента объявления переменной Type<A> type;.

В вашем случае это не создается. Компилятор мог создать экземпляр шаблона при вызове оператора, но он терпит неудачу, потому что объявление оператора шаблона не может выводить аргументы Type<A> и A*. На самом деле это сообщение об ошибке:

error: нет соответствия для 'operator ==' (типы операндов: "Тип" и "A *" )

Таким образом, неявное построение Type<A> даже не рассматривается, потому что нет функции с сигнатурой bool operator==(Type<A> l, Type<A> r), которая существует в этой точке.

Ответ 3

Вы можете определить следующий дополнительный шаблон функции:

template<typename T>
bool operator==(Type<T> l, T* r) {
    return l == Type<T>{r};
}

Тело этого шаблона явно конструирует объект Type<T>, необходимый вашему шаблону функции, чтобы правильно выводить T, чтобы он мог быть создан.

Таким образом, type == &a приведет к вызову для экземпляра этого шаблона функции, который, в свою очередь, вызывает создание экземпляра вашего шаблона функции bool operator==(Type<T> l, Type<T> r).

Ответ 4

Ну, ошибка компилятора:

error: нет соответствия для 'operator ==' (типы операндов: "Тип" и "A *" )

и вы используете typename T для обоих параметров, и это не может работать, поскольку типы не совпадают.

Считайте также использование чего-то подобного:

template<typename T, typename U> 
bool operator==(Type<T> l, U r)
{
    return true;
}