Error with multiple template in operator overloading

Simply, I tried overloading '+' operator for vector container. When I do this,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template<class T>
std::vector<T> operator+(const std::vector<T>& vec1, const std::vector<T>& vec2)
{
    std::vector<T> ret(vec1.size());
    for (size_t i = 0; i < len; i++) { ret[i] = vec1[i] + vec2[i]; }

    return ret;
}

int main()
{
    vector<int> a = {1,2,3};
    vector<int> b = {4,5,6};
    vector<int> c = a + b;
}


It works nicely (as expected). But when I try to define multiple types in template, like,

1
2
3
4
5
6
7
8
template<class T1, class T2, class rT>
std::vector<rT> operator+(const std::vector<T1>& vec1, const std::vector<T2>& vec2)
{
    std::vector<rT> ret(vec1.size());
    for (size_t i = 0; i < len; i++) { ret[i] = vec1[i] + vec2[i]; }

    return ret;
}


This throws error saying "no operator "+" matches these operands". I want to do something like,

1
2
3
4
vector<int> a = {1,2,3};
vector<double> b = {1.5,2.5,3.5};
vector<int> c = a + b;
vector<double> d = b - a;


Any tip on where am I tripping? I tried Googling a bit but nothing came up. Thank you for your time.

Edit: To clarify, I am looking for a way to deduce the return type from which variable the data is being assigned to.
Last edited on
> Any tip on where am I tripping?

The type rT in
1
2
template<class T1, class T2, class rT>
std::vector<rT> operator+(const std::vector<T1>& vec1, const std::vector<T2>& vec2) ;

can't be deduced (inferred).

Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <vector>
#include <type_traits>

// https://en.cppreference.com/w/cpp/types/common_type
template < typename T1, typename T2 >
std::vector< typename std::common_type<T1,T2>::type > operator+ ( const std::vector<T1>& a, const std::vector<T2>& b )
{
    if( a.size() < b.size() ) return b+a ;

    std::vector< typename std::common_type <T1,T2>::type > result( a.begin(), a.end() ) ;
    for( std::size_t i = 0 ; i < b.size() ; ++i ) result[i] += b[i] ;
    return result ;
}

http://coliru.stacked-crooked.com/a/2653636623942ac9
Last edited on
@JLBorges
I see my problem. Your solution works fine as well. But it returns a common type. I want to specify the return type as well which may not be the common type between the arguments. Any way to do that?
> I want to specify the return type as well which may not be the common type between the arguments.
> Any way to do that?

Provide an explicit template argument. For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <iostream>
#include <vector>
#include <type_traits>
#include <concepts>

template< typename RESULT_TYPE, typename T1,  typename T2 >
std::vector<RESULT_TYPE> plus( const std::vector<T1>& a, const std::vector<T2>& b )
{
    if( a.size() < b.size() ) return plus<RESULT_TYPE>(b,a) ;

    std::vector<RESULT_TYPE> result( a.begin(), a.end() ) ;
    for( std::size_t i = 0 ; i < b.size() ; ++i ) result[i] += b[i] ;
    return result ;
}

template < typename T1, typename T2 > // deduce result to be the vector of the common type
auto operator+ ( const std::vector<T1>& a, const std::vector<T2>& b )
{
    return plus< typename std::common_type <T1,T2>::type >( a, b ) ;
}

int main()
{
    const std::vector<int> a = { 1, 2, 3, 4, 5 };
    const std::vector<unsigned long long> b = { 1, 2, 3, 4, 5, 6, 7 };

    // specify the result type as vector of float
    const auto result_flt = plus<float>(a,b) ; // std::vector<float>
    static_assert( std::same_as< float, decltype(result_flt)::value_type > ) ;

    // deduce the result type as vector of common type
    const auto result_deduced = a+b ; // std::vector<unsigned long long>
    static_assert( std::same_as< unsigned long long, decltype(result_deduced)::value_type > ) ;
    
    std::cout << "ok\n" ;
}

http://coliru.stacked-crooked.com/a/efc9ca840e7ad5f5
Thanks for your help. Apparently, what I want to do is not possible. I wanted to specify the return type for overloaded operator. So that, in use something like this would be possible
1
2
3
vector<int> a = //something;
vector<double> b = //something;
vector<int> c = a+b;
We can use an expression template to hold the result of the + expression;
the result could then be evaluated at a later stage as needed.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <vector>

template< typename T1,  typename T2 > struct plus_result // rudimentary expression template
{
    plus_result( const std::vector<T1>& a, const std::vector<T2>& b ) : a(a), b(b) {}

    template < typename RESULT_TYPE >
    operator std::vector<RESULT_TYPE>() const // evaluated when required
    {
        if( a.size() < b.size() ) return plus_result<T2,T1>(b,a) ;

        std::vector<RESULT_TYPE> result( a.begin(), a.end() ) ;
        for( std::size_t i = 0 ; i < b.size() ; ++i ) result[i] += b[i] ;
        return result ;
    }

    const std::vector<T1>& a ;
    const std::vector<T2>& b ;
};

template< typename T1,  typename T2 > // return expression template
plus_result<T1,T2> operator+ ( const std::vector<T1>& a, const std::vector<T2>& b ) { return {a,b} ; }

int main()
{
    const std::vector<int> a = { 1, 2, 3, 4, 5 };
    const std::vector<double> b = { 1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7 };

    const std::vector<float> vec_flt = a + b ; // plus_result<int,double>(a,b).operator std::vector<float>() ;
    for( float f : vec_flt ) std::cout << f << ' ' ;
    std::cout << '\n' ;

    // note: int + double => long long results in loss of fractional part
    const std::vector<long long> vec_ll = a + b ; // plus_result<int,double>(a,b).operator std::vector<long long>() ;
    for( long long v : vec_ll ) std::cout << v << ' ' ;
    std::cout << '\n' ;
}

http://coliru.stacked-crooked.com/a/76631a05fb66ca32
Last edited on
Topic archived. No new replies allowed.