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

  • A+
Category:Languages

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

 


One possible solution is to use another function template name and type discriminators to allow argument-dependent name lookup to find the associated function in the namespace of the arguments:

template<class T> struct Tag {}; template<class T> Tag<void> tag(T const&);  template<class It1, class It2> void mycopy(It1 first, It1 second, It2 d_first, Tag<void>) {     std::cout << "std::copy/n"; }  template<class It1, class It2> void mycopy(It1 first, It1 second, It2 d_first) {     mycopy(first, second, d_first, decltype(tag(first)){}); }  namespace N{      struct itA{using trait = void;};     Tag<itA> tag(itA);      template<class It1, class It2>     void mycopy(It1 first, It1 second, It2 d_first, Tag<itA>) {         std::cout << "N::mycopy/n";     } }  int main() {     char* p = 0;     mycopy(p, p, p); // calls std::copy      N::itA q;     mycopy(q, q, q); // calls N::mycopy } 

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: