Как написать оператор == для работы с неявно литыми/построенными типами
Почему это не работает, поскольку есть возможность "конструировать" неявно?
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;
}