У меня есть следующее определение класса:
template <typename T>
class MyBox {
public:
MyBox(T value) { _value = value; }
operator T() const { return _value; }
private:
T _value;
};
typedef MyBox<int> MyInt;
typedef MyBox<std::string> MyString;
Когда я пытаюсь использовать операторы на моих typedefs, как это
bool first = MyInt(1) == MyInt(1); // works
bool second = std::string(MyString("a")) == std::string(MyString("a")); //works
bool third = MyString("a") == MyString("a"); // does not compile
компилятор жалуется на третье сравнение
ни один оператор «==» не соответствует этим операндам. Типы операндов: MyString == MyString
и это происходит с любым другим не примитивным боксом (например, MyBox<float>
работает но MyBox<std::map<int,int> >
не. Почему это так?
Это особенно неясно для меня, потому что для первого и второго сравнения operator T()
используется — почему это не может быть сделано автоматически для MyString
также?
ОБНОВИТЬ: Есть ли простое решение для этого, кроме предоставления конкретных операторов для каждого не примитивного шаблона? И что делать с MyString("a") == std::string("a")
?
Причины того, почему он работает для встроенных типов, но не работает для пользовательских типов, даны в следующем SO-вопросе: использование пользовательских преобразований с неявными преобразованиями в сравнениях. Короче говоря, это происходит потому, что преобразование типов не происходит для типов, выведенных из шаблона. И пока встроенный operator==
за int
не является шаблоном (и, следовательно, может быть найдено с помощью преобразования типа, когда MyBox<int>
используется), operator==
за std::string
это шаблон.
Тем не менее, вопрос, упомянутый выше, не содержит подробностей о том, как решить эту проблему. Вот как: добавить следующие бесплатные функции
template<class T>
bool operator==(const MyBox<T>& lhs, const MyBox<T>& rhs) {
return static_cast<const T&>(lhs) == static_cast<const T&>(rhs);
}
template<class T>
bool operator==(const MyBox<T>& lhs, const T& rhs) {
return static_cast<const T&>(lhs) == rhs;
}
template<class T>
bool operator==(const T& lhs, const MyBox<T>& rhs) {
return lhs == static_cast<const T&>(rhs);
}
Ваш второй пример использует operator==
из std::string
, строки построены из std::string(const std::string&)
(поскольку MyString::operator std::string ()
определено):
bool second = std::string(MyString("a")) == std::string(MyString("a")); // cals std::string::operator==()
Ваш третий пример не может работать: нет operator==
это занимает два MyString
s:
bool third = MyString("a") == MyString("a"); // does not compile
Я не знаю почему, и я рассмотрю это, но есть специальное правило (стандарт или реализация), которое делает operator==
можно найти для любого параметра шаблона POD MyBox
:
#include <iostream>
#include <string>
template <typename T>
class MyBox {
public:
MyBox(T value) { _value = value; }
operator T() const { return _value; }
private:
T _value;
};
struct S {};
int main()
{
MyBox<int> zero(0), one(1);
std::cout << (zero == one) << std::endl; // false
MyBox<void*> p1(&zero), p2(&one);
std::cout << (p1 == p2) << std::endl; // false
MyBox<S> s1(S{}), s2(S{});
std::cout << (s1 == s2) << std::endl; // error: no match for 'operator==' (operand types are 'MyBox<S>' and 'MyBox<S>')
}