2

I want my overload operator+ to work for mixed types. There's no problem with non-template class. To make it work with template class, I added a friend operator+ inside class and it works.

template <typename T> class Wrapper
{
    T _val;
public:
    Wrapper(T val) :_val(val){}
    T getValue() const { return _val; }

    friend Wrapper<T> operator+(const Wrapper<T>& val1, const Wrapper<T>& val2)
    {
        return Wrapper<T>(val1.getValue() + val2.getValue());
    }
};

int main()
{
    Wrapper<int> v1 = 10; // OK, implicit constructor
    Wrapper<int> v2(20);
    Wrapper<int> result1 = v1 + v2; // OK, both values are of type Wrapper<int>
    Wrapper<int> result2 = v1 + 40; // Ok, casting by implicit constructor works
    return 0;
}

Now I want to move the operator+ implementation outside the class like this:

#include <iostream>
#include <string>

template <typename T> class Wrapper;

template <typename T> Wrapper<T> operator+(const Wrapper<T>& val1, const Wrapper<T>& val2);

template <typename T> class Wrapper
{
    T _val;
public:
    Wrapper(T val) :_val(val){}
    T getValue() const { return _val; }

    friend Wrapper<T> operator+ <>(const Wrapper<T>& val1, const Wrapper<T>& val2);
};

// template<class T> Wrapper<T> operator+(const Wrapper<T>&, const Wrapper<T>&)
// template argument deduction/substitution failed
template <typename T> Wrapper<T> operator+(const Wrapper<T>& val1, const Wrapper<T>& val2)
{
    return Wrapper<T>(val1.getValue() + val2.getValue());
}

int main()
{
    Wrapper<int> v1 = 10; // OK, implicit constructor
    Wrapper<int> v2(20);
    Wrapper<int> result1 = v1 + v2; // OK, both values are of type Wrapper<int>

    // note: mismatched types 'const Wrapper<T>' and 'int'
    Wrapper<int> result2 = v1 + 40; // Error
    return 0;

}

but it give me compiling errors (pasted them into the code above). Is it possible to fix it?

http://cpp.sh/5j5zg (working) http://cpp.sh/9saow (not working)

amplifier
  • 1,793
  • 1
  • 21
  • 55

1 Answers1

1

It's a little bit weird to make a friend function of this sort that's not a template function. You can change it around a bit to get it to work, however, by making the friend operator+ a template function:

template <typename T>
class Wrapper
{
    T _val;
public:
    Wrapper(T val) :_val(val){}
    T getValue() const { return _val; }

    template <typename U>
    friend Wrapper<U> operator+(const Wrapper<U>& val1, const Wrapper<U>& val2);
};

template <typename T>
Wrapper<T> operator+(const Wrapper<T>& val1, const Wrapper<T>& val2)
{
    return Wrapper<T>(val1.getValue() + val2.getValue());
}

This almost works as you intend, but the implicit conversion is disabled since this is a template function. It's easy enough to add them back in, though:

template <typename T>
Wrapper<T> operator+(const Wrapper<T>& val1, const T& val2)
{
    return Wrapper<T>{ val1.getValue() + val2 };
}

template <typename T>
Wrapper<T> operator+(const T& val1, const Wrapper<T>& val2)
{
    return Wrapper<T>{ val1 + val2.getValue() };
}

Live on Coliru

Justin
  • 24,288
  • 12
  • 92
  • 142