Search code examples
c++templatesc++11arithmetic-expressionstype-promotion

How to promote two template types for arithmitic operations like builtin types do?


If I have a generic struct/class:

template<typename T>
struct Container
{
    T value;
    Container(const Value& value) : value(value) { }
};

And I want to perform an operation on two of them:

template<typename T, typename U>
Container<T> operator+(const Container<T>& lhs, const Container<U>& rhs)
{
    return Container<T>(lhs.value + rhs.value);
}

The problem is that if lhs is of the type Container<int> and rhs is of the type Container<float>, then I'll get a Container<int> back. But if I were to do auto result = 2 + 2.0f, then result would of of type float. So the behavior is inconsistent between builtin types and custom types.

So how would I take the operator+ overload and make it return Container<float>, much like how C++ handles arithmetic promotion with builtin types?


Solution

  • As far as you use one of the two types of the template, you risk to induce a cast on the result of the sum. As an example, if you accidentally choose int as your target type, even though the sum results in a float, it will be cast down to the chosen type.

    Anyway, starting with C++11, you con rely on the decltype specifier as in the example above (or at least, you can do that if Container::T and Container::U are a types for which the + operator is defined).

    I used also the auto specifier as return value for the operator+, for it is at our disposal starting from C++14 and it's really useful indeed.

    It follows the working example above mentioned:

    #include <iostream>
    #include <vector>
    
    template<typename T>
    struct Container
    {
        T value;
        Container(const T& value) : value(value) { }
    };
    
    template<typename T, typename U>
    auto operator+(const Container<T>& lhs, const Container<U>& rhs)
    {
        return Container<decltype(lhs.value+rhs.value)>{lhs.value + rhs.value};
    }
    
    int main()
    {
        Container<int> c1{1};
        Container<float> c2{0.5};
        std::cout << (c1+c2).value << std::endl;
    }