c++c++11operator-overloadinggreatest-common-divisorgeneralization

GCD of multiple parameters


My aim was to generalize the __gcd() available in std <algorithm> header in C++. which should be able to call for a range of values of a std::vector array.

The generalized template __gcd() works perfectly when parameters have been passed directly. Just like below:

math::GCD(1,2,58,54);

However, when I tried to pass a range of values of a vector(the code is given below), it shows the following error:

D:\Programming\C++\CPP Programs\My Test\My Test.cpp|33|error: no match for 'operator<<' (operand types are 'std::ostream {aka std::basic_ostream<char>}' and '__gnu_cxx::__normal_iterator<int*, std::vector<int> >')|

I don't know how to overload operator<< or include an overload function in this template/ program.(assuming that the error is due to overloading of operator<< has missed)

namespace math
{

    template <typename M, typename N>
    constexpr auto GCD(const M& m, const N& n) {
        return __gcd(m, n);
    }

    template <typename M, typename ...Rest>
    constexpr auto GCD(const M& first, const Rest&... rest) {
        return __gcd(first, GCD(rest...));
    }
}

int main()
{
    vector<int> vec={1,2,58,54,102,2,37,13,8};
    for(auto i=0; i<vec.size()-3; ++i)
        cout<<math::GCD(vec.begin()+i, vec.begin()+i+4)<<endl;
    return 0;
}

can anybody help me to overload operator<< or (if it's not the case) to find the error? thanks in advance.


Solution

  • I have done it finally. Thanks for @Incomputable 's last comment. However, I had to make a separation between the new template(for iterators) and the two we had in the question using math name. Just like as follows:

    #include <iostream>
    #include <vector>
    
    template<typename T64> constexpr  T64 calcGCD(T64 a, T64 b)
    {
        return (a==0 && b!=0) ? b: a;
        while(b)
        {
            T64 t = a % b;
            b = a;
            a = t;
        }
        return a;
    }
    
    template <typename Iterator> constexpr auto GCD(Iterator first, Iterator last)
    {
        auto itrFirst = first;
        auto itrEnd   = last;
        int Size      = std::distance(itrFirst,itrEnd);
        int Result = 0;
    
        if(Size >=2 )
        {
            int A       = *itrFirst;
            std::advance (itrFirst,1);
            int B       = *itrFirst;
    
            Result      = calcGCD(A,B);
            std::advance (itrFirst,1);
    
            for(int i = 2; i<Size; ++i)
            {
                A       = *itrFirst;
                Result  = calcGCD(Result,A);
                std::advance (itrFirst,1);
            }
        }
        else   return *itrFirst;
        return Result;
    }
    
    namespace math
    {
        template <typename M, typename N>
        constexpr auto GCD(const M& m, const N& n)
        { return calcGCD(m, n); }
    
        template <typename M, typename ...Rest>
        constexpr auto GCD(const M& first, const Rest&... rest)
        { return calcGCD(first, GCD(rest...));  }
    }
    
    
    int main()
    {
        std::vector<int> vec={1,2,58,54,102,2,37,13,8};
    
        std::cout<<"GCD from Iterator Template     : ";
        for(unsigned int i=0; i<vec.size()-3; ++i)
          std::cout<<GCD(vec.begin()+i, vec.begin()+i+4)<<" ";
    
        std::cout<<std::endl;
    
        std::cout<<"GCD from non-iterator Templates: ";
        std::cout<<math::GCD(1,2,58,54)<<" ";
        std::cout<<math::GCD(2,58,54,102)<<" ";
        std::cout<<math::GCD(58,54,102,2)<<" ";
        std::cout<<math::GCD(54,102,2,37)<<" ";
        std::cout<<math::GCD(102,2,37,13)<<" ";
        std::cout<<math::GCD(2,37,13,8)<<" ";   
    
        return 0;
    }
    

    It gives the required output as expected. However, I haven't tested for any other cases.

    Out Put:

    GCD from Iterator Template     : 1 2 58 54 102 2 
    GCD from non-iterator Templates: 1 2 58 54 102 2