Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Operator overloading outside a template class with implicit conversions

I have a template class defined like this

template<class T> class Wrap
{
    /* ... */
public:
    Wrap(const T&);
    /* other implicit conversions */

    /* ... */
};

I want to define all the comparison operators for this class outside the class like this

template<typename T> bool operator == (const Wrap<T>&, const Wrap<T>&)
{
    // Do comparison here
}

This declaration however doesn't support implicit conversions of const T&, or any other type, to const Wrap<T>&.

So my question is how do I make it support implicit conversions when either one of the operands is of type Wrap<T> and the other is not. I don't want to write multiple declarations of each operator for every possible permutation.

like image 616
user1353535 Avatar asked Jun 23 '13 10:06

user1353535


People also ask

Can you overload operator outside of class?

Therefore, you may not overload them outside the class, since they are not allowed to be defined outside the class in the first place.

Can we overload operator outside class C++?

In C++, you can't overload: The member selection dot . operator.

What is operator overloading give example for overloading<< and>> operator?

This means C++ has the ability to provide the operators with a special meaning for a data type, this ability is known as operator overloading. For example, we can overload an operator '+' in a class like String so that we can concatenate two strings by just using +.

What is operator overloading explain conversion?

The operator overloading defines a type conversion operator that can be used to produce an int type from a Counter object. This operator will be used whenever an implicit or explict conversion of a Counter object to an int is required. Notice that constructors also play a role in type conversion.


2 Answers

template<class T> struct is_wrap : std::false_type {};
template<class T> struct is_wrap<Wrap<T>> : std::true_type {};

template<class T1, class T2> typename std::enable_if<is_wrap<typename std::common_type<T1, T2>::type>::value, bool>::type operator == (const T1& t1, const T2& t2)
{
    const typename std::common_type<T1, T2>::type& tc1 = t1, tc2 = t2;
    // compare with tc1 and tc2
}
like image 81
siddhu323 Avatar answered Sep 28 '22 10:09

siddhu323


Someone else will articulate this better, but I think the problem is that the compiler can't deduce T in Wrap<T> without you passing it a Wrap object. I think your situation should be resolved if you explicitly give the operator== a template argument: operator==<int>(7, 4), for example should work.

I don't have a compiler in front of me, but here's my try:

template<typename T>
typename std::enable_if<std::is_convertible<Wrap<T>, T>::value, bool>::type operator==(const Wrap<T>& l, const T& r)
{
    return l.stuff == Wrap<T>(r).stuff;
}

template<typename T>
typename std::enable_if<std::is_convertible<Wrap<T>, T>::value, bool>::type operator==(const T& l, const Wrap<T>& r)
{
    return r == l; // call above operator
}

This should work if either side is a Wrap and the other side isn't. You could also do both sides as const T&, however if Wrap is really implicitly constructible from any T you will wind up using your operator== for many unintended comparisons, even of ints, strings, etc.

like image 29
David Avatar answered Sep 28 '22 09:09

David