lundi 28 janvier 2019

How to write a standard-like function that has higher overload priority than the std version

In a generic function I use the following idiom

template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first){
    using std::copy;
    copy(first, second, d_first);
}

Now suppose I have several iterator in my namespace N.

namespace N{

  struct itA{using trait = void;};
  struct itB{using trait = void;};
  struct itC{using trait = void;};

}

An I want to overload copy for these iterators in this namespace. Naturally I would do:

namespace N{
    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
        std::cout << "here" << std::endl;
    }
}

However when I call do_something with N::A, N::B or N::C argument I get "ambiguous call to copy" even though these are in the same namespace as N::copy.

Is there a way to win over std::copy in the context of the original function above?

I though that if I put constrains over the template arguments then N::copy would be preferred.

namespace N{
    template<class SomeN1, class SomeN2, typename = typename SomeN1::trait>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
        std::cout << "here" << std::endl;
    }
}

but it doesn't help.

What other workarounds can I try for the generic call to copy to prefer to a copy in the namespace of arguments rather than std::copy.

Complete code:

#include<iostream>
#include<algorithm>
namespace N{
  struct A{};
  struct B{};
  struct C{};
}

namespace N{
    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
        std::cout << "here" << std::endl;
    }
}

template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first){
    using std::copy;
    copy(first, second, d_first); // ambiguous call when It is from namespace N (both `std::copy` and `N::copy` could work.
}

int main(){
    N::A a1, a2, a3;
    do_something(a1, a2, a3); 
}

A typical error message is

error: call of overloaded ‘copy(N::A&, N::A&, N::A&)’ is ambiguous

Aucun commentaire:

Enregistrer un commentaire