Gutek
Gutek

Reputation: 21

Return type deduction failure in overloaded operator

So I have this class template with a single attribute value of type T where I try to overload the + operator, s.t. adding two objects of this class results in another object of this class where the value is the sum of the values of the two. Here's the code:

template<typename T>
class Number
{
    public:
        //constructors
        Number(T value)
        : value(value) {}

        //attributes
        const T value;

        //operators
        //addition +
        template<typename U>
        auto operator+(Number<U> other)
        {
            auto val = this->value + other.value;
            Number output(val); //instantiating object of class Number, using constructor
            std::cout << "output value: "<<output.value << std::endl;
            std::cout << "auto val: "<< val << std::endl;

            return output;
        }
};

int main()
{
    Number<int> x(2);
    Number<float> y(2.5);
    Number z=x+y;

    std::cout << "x = " << x.value << std::endl;
    std::cout << "y = " << y.value << std::endl;
    std::cout << "x+y = " << z.value << std::endl;


    return 0;
}

. The output is:

output value:4 
auto val: 4.5 
x = 2 
y = 2.5 
x+y = 4

. Obviously there occurs and undesired type conversion, from float to int and I am trying to find out how to avoid this without resorting to specialization. Explicit declaration of the operator output type does not compile. I understand that here the failure lies in that the auto type output becomes the type Number<T>, which in this case is Number<int> but does it have to be int even when a new object is instantiated within the operator definition scope { }? I'd appreciate some help in this simple exercise, thank you in advance!

Upvotes: 2

Views: 87

Answers (1)

fabian
fabian

Reputation: 82461

As @NathanPierson mentioned:

Number refers to Number<T> inside the operator. You unfortunately cannot use template argument deduction here.

The return type can be determined based on the type of the additon though. You could use a trailing return type to specify the return type. This assumes you don't need to use the result before returning from the function.

class Number
{
public:
    ...

    template<typename U>
    auto operator+(Number<U> other) -> Number<decltype(other.value + value)>
    {
        return {value + other.value};
    }

};

.

You could also implement the operator in namespace scope:

template<class T, class U>
auto operator+(Number<T> const& s1, Number<U> const& s2)
{
    auto val = s1.value + s2.value;
    Number result(val);
    return result;
}

Upvotes: 1

Related Questions