0

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
  • The function is not doing what you think it does. I mean gcd. – Incomputable Mar 01 '18 at 07:59
  • 1
    All symbols starting with double underscore are reserved for the implementation (i.e. they are considered *internal* for the compiler and standard library). They are inherently not portable. Unless explicitly documented (like `__cplusplus`) you should *not* use such symbols or define your own symbols with those names. Also see [What are the rules about using an underscore in a C++ identifier?](https://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – Some programmer dude Mar 01 '18 at 08:00
  • As for your problem, you need to add a specialization of `math::GCD` where `M` and `N` are *iterators*, and then you need to loop over the iterators and call the generic two-argument `math::GCD` in each iteration. And if that's not what you're supposed to do, then you have to rethink your approach from the ground up. – Some programmer dude Mar 01 '18 at 08:06
  • 2
    @Someprogrammerdude: then the question is how come, `math::GCD(1,2,58,54);` works for the same implementation, which should not be also possible as per the above-mentioned content, since I have used `__gcd` in it. Obviously, it's not an iterator passing case. –  Mar 01 '18 at 08:08
  • 2
    @Incomputable : it's not taking the range of iterator, that's what I understood from Someprogrammerdude's comment. –  Mar 01 '18 at 08:13
  • @Jackyone, iterator operations must be constexpr in order to have any hope of using your syntax. Just overload the function – Incomputable Mar 01 '18 at 08:16
  • 1
    Your call `math::GCD(vec.begin()+i, vec.begin()+i+4)` calls the two-argument `math::GCD` function, not the parameter pack function. I don't know what `__gcd` is or how it's declared (it is an ***internal*** and ***implementation-specific*** and ***undocumented*** function that no one in their right mind should use) but it probably doesn't take two iterators. That means the call to `math::GCD` will not work and the call to `operator<<` will fail. I doubt the error message you show is the *only* output you get from the compiler. Please copy-paste the *full* and *complete* output. – Some programmer dude Mar 01 '18 at 08:19
  • 2
    @Someprogrammerdude: I have added the link to the compiler Build msg. –  Mar 01 '18 at 08:24
  • 1
    @Incomputable: And I don't know how that should have been done. –  Mar 01 '18 at 08:25
  • 2
    @Jackyone, just use `template auto gcd(InputIterator first, InputIterator last)` as declaration, and google some more about `InputIterator`. Iterators are very important concept, so learning them will be quite valuable. – Incomputable Mar 01 '18 at 08:27
  • __gcd is not standard. In C++17, there is a `std::gcd` in ``. – Jive Dadson Mar 01 '18 at 09:08
  • Please never post ephemeral content like paste.ofcode.org on Stack Overflow. – Cœur Mar 27 '18 at 01:21

1 Answers1

0

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