How to write a standard-like function that has high overload priority

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP












16















In a generic function I use the following idiom,



template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first)
... other stuff here...
using std::copy;
copy(first, second, d_first);



do_something is a generic function that shouldn't know anything specific about any other libraries (except perhaps std::).



Now suppose I have several iterator in my namespace N.



namespace N

struct itAusing trait = void;;
struct itBusing trait = void;;
struct itCusing 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




Am I right to think that C++ Concepts will help here by preferring function calls with more contraints than less constraints?










share|improve this question



















  • 1





    Not a dupe, but related.

    – lubgr
    Jan 28 at 11:19






  • 1





    Obviously the error comes from always doing using std::copy;.

    – Matthieu Brucher
    Jan 28 at 11:20






  • 3





    @alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

    – Maxim Egorushkin
    Jan 28 at 11:27







  • 2





    @MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

    – alfC
    Jan 28 at 11:33






  • 1





    @geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

    – alfC
    Jan 28 at 11:36















16















In a generic function I use the following idiom,



template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first)
... other stuff here...
using std::copy;
copy(first, second, d_first);



do_something is a generic function that shouldn't know anything specific about any other libraries (except perhaps std::).



Now suppose I have several iterator in my namespace N.



namespace N

struct itAusing trait = void;;
struct itBusing trait = void;;
struct itCusing 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




Am I right to think that C++ Concepts will help here by preferring function calls with more contraints than less constraints?










share|improve this question



















  • 1





    Not a dupe, but related.

    – lubgr
    Jan 28 at 11:19






  • 1





    Obviously the error comes from always doing using std::copy;.

    – Matthieu Brucher
    Jan 28 at 11:20






  • 3





    @alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

    – Maxim Egorushkin
    Jan 28 at 11:27







  • 2





    @MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

    – alfC
    Jan 28 at 11:33






  • 1





    @geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

    – alfC
    Jan 28 at 11:36













16












16








16


3






In a generic function I use the following idiom,



template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first)
... other stuff here...
using std::copy;
copy(first, second, d_first);



do_something is a generic function that shouldn't know anything specific about any other libraries (except perhaps std::).



Now suppose I have several iterator in my namespace N.



namespace N

struct itAusing trait = void;;
struct itBusing trait = void;;
struct itCusing 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




Am I right to think that C++ Concepts will help here by preferring function calls with more contraints than less constraints?










share|improve this question
















In a generic function I use the following idiom,



template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first)
... other stuff here...
using std::copy;
copy(first, second, d_first);



do_something is a generic function that shouldn't know anything specific about any other libraries (except perhaps std::).



Now suppose I have several iterator in my namespace N.



namespace N

struct itAusing trait = void;;
struct itBusing trait = void;;
struct itCusing 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




Am I right to think that C++ Concepts will help here by preferring function calls with more contraints than less constraints?







c++ c++11 ambiguous argument-dependent-lookup






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jan 29 at 0:24







alfC

















asked Jan 28 at 11:13









alfCalfC

5,08722960




5,08722960







  • 1





    Not a dupe, but related.

    – lubgr
    Jan 28 at 11:19






  • 1





    Obviously the error comes from always doing using std::copy;.

    – Matthieu Brucher
    Jan 28 at 11:20






  • 3





    @alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

    – Maxim Egorushkin
    Jan 28 at 11:27







  • 2





    @MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

    – alfC
    Jan 28 at 11:33






  • 1





    @geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

    – alfC
    Jan 28 at 11:36












  • 1





    Not a dupe, but related.

    – lubgr
    Jan 28 at 11:19






  • 1





    Obviously the error comes from always doing using std::copy;.

    – Matthieu Brucher
    Jan 28 at 11:20






  • 3





    @alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

    – Maxim Egorushkin
    Jan 28 at 11:27







  • 2





    @MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

    – alfC
    Jan 28 at 11:33






  • 1





    @geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

    – alfC
    Jan 28 at 11:36







1




1





Not a dupe, but related.

– lubgr
Jan 28 at 11:19





Not a dupe, but related.

– lubgr
Jan 28 at 11:19




1




1





Obviously the error comes from always doing using std::copy;.

– Matthieu Brucher
Jan 28 at 11:20





Obviously the error comes from always doing using std::copy;.

– Matthieu Brucher
Jan 28 at 11:20




3




3





@alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

– Maxim Egorushkin
Jan 28 at 11:27






@alfC Your N::copy is also a function template that has no arguments associated with namespace N. Hence, it is not better than std::copy for the purpose of overload resolution.

– Maxim Egorushkin
Jan 28 at 11:27





2




2





@MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

– alfC
Jan 28 at 11:33





@MatthieuBrucher, if I use std::copy then there is no chance the special version of copy is called. The only way would be to overload std::copy (in the namespace std) which I don't know if it is allowed.

– alfC
Jan 28 at 11:33




1




1





@geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

– alfC
Jan 28 at 11:36





@geza, the problem is that do_something is a template function that doesn't know about the namespace N or the library N.

– alfC
Jan 28 at 11:36












7 Answers
7






active

oldest

votes


















4














You can declare copy() as a public friend function in your iterator classes.
This works kind of as a replacement for partial specialization (which is impossible for functions), so that they will be preferred by overload resolution as they are more specialized:



#include <iostream>
#include <algorithm>
#include <vector>

namespace N

template<class SomeN1, class SomeN2>
SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

std::cout << "here" << std::endl;
return d_first;


template <class T>
struct ItBase

template <class SomeN2>
friend SomeN2 copy(T first, T last, SomeN2 d_first)

return N::copy(first, last, d_first);

;

struct A : ItBase<A>;
struct B : ItBase<B>;
struct C : ItBase<C>;


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


int main()
N::A a1, a2, a3;
std::cout << "do something in N:" << std::endl;
do_something(a1, a2, a3);

std::vector<int> v = 1,2,3;
std::vector<int> v2(3);
std::cout << "do something in std:" << std::endl;
do_something(std::begin(v), std::end(v), std::begin(v2));
for (int i : v2)
std::cout << i;
std::cout << std::endl;



See this demo to verify that it works.



I introduced a common base class that declares the necessary friends for all of your iterators. So, instead of declaring a tag, as you tried, you just have to inherit from ItBase.



Note: If N::copy() is supposed to work with only these iterators in N, it might not be needed anymore as these friend functions will be publicly visible in N anyway (as if they were free functions).




Update:



In the comments, it has been suggested, if the iterators in N have a common base class anyway, to just declare N::copy with this base class, e.g.



namespace N

template <class SomeN2>
SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) ...



Unfortunately, this would have the opposite effect of the desired one: std::copy will always be preferred over N::copy because if you pass an instance of A, it would have to be downcasted in order to match N::copy while no cast is required for std::copy. Here you can see that obviously std::copy is tried to be called (which gives an error because N::A lacks some typedefs).



So, you cannot leverage a common base class for the signature of N::copy. The one and only reason I used one in my solution was to avoid duplicate code (having to declare the friend function in every iterator class). My ItBase does not participate in overload resolution at all.



Note, however, if your iterators happen to have some common members (whether derived from some common base class or not is not important) that you want to use in your implementation of N::copy, you can just do that with my solution above like so:



namespace N

template <class T>
struct ItBase

template <class SomeN2>
friend SomeN2 copy(T first, T last, SomeN2 d_first)

first.some_member();
last.some_member();
return d_first;

;

struct A : ItBase<A> void some_member() ;
struct B : ItBase<B> void some_member() ;
struct C : ItBase<C> void some_member() ;



See here how it works.




On the same lines, if A, B, C have common behavior then it could be possible to replaced them by common template class parameterized in some way.



namespace N

template <class T, int I>
struct ItCommon

...
;
using A = ItCommon<double,2>;
using B = ItCommon<int, 3>;
using C = ItCommon<char, 5>;

...
namespace N
template<class T, int I, class Other>
SomeN2 copy(ItCommon<T, I> first, ItCommon<T, I> last, Other)
...




Since this (non-friend) copy function is definitely more constrained than the std::copy and because of ADL, it will have high priority when one of the arguments belongs to the N namespace. Also, being a non-friend, this copy function is an optional component.






share|improve this answer

























  • This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

    – alfC
    Jan 29 at 14:29











  • @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

    – sebrockm
    Jan 29 at 15:14











  • Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

    – alfC
    Jan 29 at 16:04











  • BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

    – alfC
    Jan 29 at 16:08






  • 1





    @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

    – sebrockm
    Jan 30 at 9:48


















3














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::copyn";


template<class It1, class It2>
void mycopy(It1 first, It1 second, It2 d_first)
mycopy(first, second, d_first, decltype(tag(first))); // Discriminate by the type of It1.


namespace N

struct itAusing 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::mycopyn";



int main()
char* p = 0;
mycopy(p, p, p); // calls std::copy

N::itA q;
mycopy(q, q, q); // calls N::mycopy






share|improve this answer
































    2














    This seems to fulfill your requirements:



    namespace SpecCopy 

    template <typename A, typename B, typename C>
    void copy(A &&a, B &&b, C &&c)
    std::copy(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));




    template<class It1, class It2>
    void do_something(It1 first, It1 second, It2 d_first)
    using namespace SpecCopy;
    copy(first, second, d_first);



    Basically, it depends on ADL. If no function found by ADL, then it will use SpecCopy::copy, which is a wrapper to std::copy.




    So, if you do:



    N::A a1, a2, a3;
    do_something(a1, a2, a3);


    Then do_something will call N::copy.




    If you do:



    std::vector<int> a1, a2;
    do_something(a1.begin(), a1.end(), a2.begin());


    Then do_something will call SpecCopy::copy, which will call std::copy.




    If you do:



    int *a1, *a2, *a3;
    do_something(a1, a2, a3);


    Then same thing happens as before: do_something will call SpecCopy::copy, which will call std::copy.






    share|improve this answer




















    • 1





      I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

      – Daniel Jour
      Jan 28 at 16:31











    • @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

      – geza
      Jan 28 at 16:58











    • @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

      – alfC
      Jan 28 at 19:03











    • @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

      – geza
      Jan 28 at 19:16












    • @alfC: I've edited my answer so you can see what I mean.

      – geza
      Jan 28 at 19:29


















    2














    In c++ 11 you could use tag dispatch. If you can make a little change to your custom iterators things will be a bit simpler to implement.



    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <type_traits>

    // indicates that the type doesn't have a tag type (like pointers and standard iterators)
    struct no_tag;

    namespace detail

    template <typename T>
    auto tag_helper(int) -> typename T::tag;

    template <typename>
    auto tag_helper(long) -> no_tag;


    // get T::tag or no_tag if T::tag isn't defined.
    template <typename T>
    using tag_t = decltype(detail::tag_helper<T>(0));

    namespace N

    struct my_iterator_tag ;
    struct A using tag = my_iterator_tag; ;
    struct B using tag = my_iterator_tag; ;
    struct C using tag = my_iterator_tag; ;


    namespace N

    template<class SomeN1, class SomeN2>
    SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

    std::cout << "calling std::copyn";
    return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


    template<class SomeN1, class SomeN2>
    SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

    // your custom copy
    std::cout << "custom copy functionn";
    return ;


    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

    return copy_helper(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first), tag_t<SomeN1>);



    template<class It1, class It2>
    void do_something(It1 first, It1 second, It2 d_first)

    N::copy(first, second, d_first);


    int main()

    N::A a1, a2, a3;
    std::cout << "using custom iterator: ";
    do_something(a1, a2, a3);

    std::cout << "using vector iterator: ";
    std::vector<int> v;
    do_something(std::begin(v), std::end(v), std::begin(v));

    std::cout << "using pointer: ";
    int* ptr = new int[10];
    do_something(ptr, ptr + 5, ptr);

    return 0;



    First we change our custom iterators to have a tag type (maybe change the name to avoid confusion with iterator_category). tag can be any type you want, it just has to match the type you use as tag in copy_helper.



    Next, we define a type that allows us to access this tag type, or to fall back to a default type if tag doesn't exist. This will help us distinguish between our custom iterators and standard iterators and pointers. The default type I use is no_tag. The tag_t provides us with this functionality by using SFINAE and overload resolution. We call the function tag_helper(0) which has two declarations. The first one returns T::tag while the second one returns no_tag. Calling tag_helper(0) will always try to use the first version because int is a better match for 0 than long. This means we will always try to access T::tag first. However if this isn't possible (T::tag is not defined) SFINAE kicks in and skipps tag_helper(int) selecting tag_helper(long).



    Finally, we just have to implement a copy function for each tag (I called it copy_helper) and another copy function as a wrap around for convinience (I used N::copy). The wrapper function then creates the proper tag type and calls the correct helper function.



    Here is a live example.



    Edit



    If you move the code around a bit you can disconnect namespace N and rely on ADL:



    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <type_traits>

    // indicates that the type doesn't have a tag type (like pointers and standard iterators)
    struct no_tag;

    namespace detail

    template <typename T>
    auto tag_helper(int) -> typename T::tag;

    template <typename>
    auto tag_helper(long) -> no_tag;


    // get T::tag or no_tag if T::tag isn't defined.
    template <typename T>
    using tag_t = decltype(detail::tag_helper<T>(0));

    namespace N

    struct my_iterator_tag ;
    struct A using tag = my_iterator_tag; ;
    struct B using tag = my_iterator_tag; ;
    struct C using tag = my_iterator_tag; ;

    template<class SomeN1, class SomeN2>
    SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

    // your custom copy
    std::cout << "custom copy functionn";
    return ;



    template<class SomeN1, class SomeN2>
    SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

    std::cout << "calling std::copyn";
    return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


    template<class It1, class It2>
    void do_something(It1 first, It1 second, It2 d_first)

    copy_helper(std::forward<It1>(first), std::forward<It1>(second), std::forward<It2>(d_first), tag_t<It1>);


    int main()

    N::A a1, a2, a3;
    std::cout << "using custom iterator: ";
    do_something(a1, a2, a3);

    std::cout << "using vector iterator: ";
    std::vector<int> v;
    do_something(std::begin(v), std::end(v), std::begin(v));

    std::cout << "using pointer: ";
    int* ptr = new int[10];
    do_something(ptr, ptr + 5, ptr);

    return 0;






    share|improve this answer

























    • Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

      – alfC
      Jan 28 at 19:00











    • @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

      – Timo
      Jan 28 at 19:38











    • @alfC I edited my answer to rely on ADL.

      – Timo
      Jan 28 at 19:49











    • The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

      – alfC
      Jan 28 at 19:58


















    1














    OK, building on @paler123, but without checking for an existing type, but checking if It1 is a pointer instead:



    namespace N
    struct A;
    struct B;
    struct C;


    namespace N
    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1, SomeN1, SomeN2 c)
    std::cout << "here" << std::endl;
    return c;


    template<class It1, class It2>
    void do_something(It1 first, It1 second, It2 d_first)
    if constexpr (std::is_pointer_v<It1>)
    std::copy(first, second, d_first);

    else

    copy(first, second, d_first);




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

    int* b1, *b2, *b3;

    do_something(b1, b2, b3);



    Still C++17, but in the case of pointers, we go through the explicit std::copy otherwise, we rely on ADL.



    In general, your issue is a design problem. You want to use std::copy for all cases, except for objects from N, and in that case, you hope that ADL will work. But as you forced std::copy, you remove the option for proper ADL. You can't have everything and you have to redesign your code.






    share|improve this answer

























    • Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

      – alfC
      Jan 28 at 11:52











    • Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

      – Matthieu Brucher
      Jan 28 at 11:55


















    1














    (These notes are now integrated in my edit to @sebrockm's answer)




    For discussion I will write an answer to my own question with an alternative option.



    It is not very nice because it needs to wrap all the N:: classes in another template class (called wrap here). The good thing is that do_something nor the N classes need to know about the special N::copy. The price is that the main caller has to explicitly wrap the N:: classes which is ugly but which is fine from the point of view of coupling because this is the only code that should know about the whole system.



    #include <iostream>
    #include <algorithm>
    #include <vector>

    namespace N
    struct A;
    struct B;
    struct C;


    namespace N

    template<class S> struct wrap : S;

    template<class SomeN1, class SomeN2>
    SomeN2 copy(wrap<SomeN1> first, wrap<SomeN1> last, wrap<SomeN2> d_first)

    std::cout << "here" << std::endl;
    return d_first;



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


    int main()
    N::wrap<N::A> a1, a2, a3;
    std::cout << "do something in N:" << std::endl;
    do_something(a1, a2, a3);

    std::vector<int> v = 1,2,3;
    std::vector<int> v2(3);
    std::cout << "do something in std:" << std::endl;
    do_something(std::begin(v), std::end(v), std::begin(v2));
    for (int i : v2)
    std::cout << i;
    std::cout << std::endl;






    share|improve this answer

























    • That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

      – Daniel Jour
      Jan 30 at 13:13


















    -2














    Suggest you have a look at the very powerful new Boost.HOF library.



    This function does exactly what you want:



    #include <boost/hof.hpp>

    template<class It1, class It2>
    void do_something(It1 first, It1 second, It2 d_first)
    namespace hof = boost::hof;

    auto my_copy = hof::first_of(
    (auto first, auto second, auto d_first) -> decltype(N::copy(first, second, d_first))

    return N::copy(first, second, d_first);
    ,
    (auto first, auto second, auto d_first) -> decltype(std::copy(first, second, d_first))

    return std::copy(first, second, d_first);
    );
    my_copy(first, second, d_first);



    hof::first_of will select the first lambda whose return type is deduced to be the result type of a legal expression.






    share|improve this answer




















    • 1





      This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

      – alfC
      Jan 28 at 20:18











    • @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

      – Richard Hodges
      Jan 29 at 0:20










    Your Answer






    StackExchange.ifUsing("editor", function ()
    StackExchange.using("externalEditor", function ()
    StackExchange.using("snippets", function ()
    StackExchange.snippets.init();
    );
    );
    , "code-snippets");

    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "1"
    ;
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function()
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled)
    StackExchange.using("snippets", function()
    createEditor();
    );

    else
    createEditor();

    );

    function createEditor()
    StackExchange.prepareEditor(
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader:
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    ,
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );













    draft saved

    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54400763%2fhow-to-write-a-standard-like-function-that-has-high-overload-priority%23new-answer', 'question_page');

    );

    Post as a guest















    Required, but never shown

























    7 Answers
    7






    active

    oldest

    votes








    7 Answers
    7






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    4














    You can declare copy() as a public friend function in your iterator classes.
    This works kind of as a replacement for partial specialization (which is impossible for functions), so that they will be preferred by overload resolution as they are more specialized:



    #include <iostream>
    #include <algorithm>
    #include <vector>

    namespace N

    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

    std::cout << "here" << std::endl;
    return d_first;


    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    return N::copy(first, last, d_first);

    ;

    struct A : ItBase<A>;
    struct B : ItBase<B>;
    struct C : ItBase<C>;


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


    int main()
    N::A a1, a2, a3;
    std::cout << "do something in N:" << std::endl;
    do_something(a1, a2, a3);

    std::vector<int> v = 1,2,3;
    std::vector<int> v2(3);
    std::cout << "do something in std:" << std::endl;
    do_something(std::begin(v), std::end(v), std::begin(v2));
    for (int i : v2)
    std::cout << i;
    std::cout << std::endl;



    See this demo to verify that it works.



    I introduced a common base class that declares the necessary friends for all of your iterators. So, instead of declaring a tag, as you tried, you just have to inherit from ItBase.



    Note: If N::copy() is supposed to work with only these iterators in N, it might not be needed anymore as these friend functions will be publicly visible in N anyway (as if they were free functions).




    Update:



    In the comments, it has been suggested, if the iterators in N have a common base class anyway, to just declare N::copy with this base class, e.g.



    namespace N

    template <class SomeN2>
    SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) ...



    Unfortunately, this would have the opposite effect of the desired one: std::copy will always be preferred over N::copy because if you pass an instance of A, it would have to be downcasted in order to match N::copy while no cast is required for std::copy. Here you can see that obviously std::copy is tried to be called (which gives an error because N::A lacks some typedefs).



    So, you cannot leverage a common base class for the signature of N::copy. The one and only reason I used one in my solution was to avoid duplicate code (having to declare the friend function in every iterator class). My ItBase does not participate in overload resolution at all.



    Note, however, if your iterators happen to have some common members (whether derived from some common base class or not is not important) that you want to use in your implementation of N::copy, you can just do that with my solution above like so:



    namespace N

    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    first.some_member();
    last.some_member();
    return d_first;

    ;

    struct A : ItBase<A> void some_member() ;
    struct B : ItBase<B> void some_member() ;
    struct C : ItBase<C> void some_member() ;



    See here how it works.




    On the same lines, if A, B, C have common behavior then it could be possible to replaced them by common template class parameterized in some way.



    namespace N

    template <class T, int I>
    struct ItCommon

    ...
    ;
    using A = ItCommon<double,2>;
    using B = ItCommon<int, 3>;
    using C = ItCommon<char, 5>;

    ...
    namespace N
    template<class T, int I, class Other>
    SomeN2 copy(ItCommon<T, I> first, ItCommon<T, I> last, Other)
    ...




    Since this (non-friend) copy function is definitely more constrained than the std::copy and because of ADL, it will have high priority when one of the arguments belongs to the N namespace. Also, being a non-friend, this copy function is an optional component.






    share|improve this answer

























    • This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

      – alfC
      Jan 29 at 14:29











    • @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

      – sebrockm
      Jan 29 at 15:14











    • Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

      – alfC
      Jan 29 at 16:04











    • BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

      – alfC
      Jan 29 at 16:08






    • 1





      @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

      – sebrockm
      Jan 30 at 9:48















    4














    You can declare copy() as a public friend function in your iterator classes.
    This works kind of as a replacement for partial specialization (which is impossible for functions), so that they will be preferred by overload resolution as they are more specialized:



    #include <iostream>
    #include <algorithm>
    #include <vector>

    namespace N

    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

    std::cout << "here" << std::endl;
    return d_first;


    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    return N::copy(first, last, d_first);

    ;

    struct A : ItBase<A>;
    struct B : ItBase<B>;
    struct C : ItBase<C>;


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


    int main()
    N::A a1, a2, a3;
    std::cout << "do something in N:" << std::endl;
    do_something(a1, a2, a3);

    std::vector<int> v = 1,2,3;
    std::vector<int> v2(3);
    std::cout << "do something in std:" << std::endl;
    do_something(std::begin(v), std::end(v), std::begin(v2));
    for (int i : v2)
    std::cout << i;
    std::cout << std::endl;



    See this demo to verify that it works.



    I introduced a common base class that declares the necessary friends for all of your iterators. So, instead of declaring a tag, as you tried, you just have to inherit from ItBase.



    Note: If N::copy() is supposed to work with only these iterators in N, it might not be needed anymore as these friend functions will be publicly visible in N anyway (as if they were free functions).




    Update:



    In the comments, it has been suggested, if the iterators in N have a common base class anyway, to just declare N::copy with this base class, e.g.



    namespace N

    template <class SomeN2>
    SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) ...



    Unfortunately, this would have the opposite effect of the desired one: std::copy will always be preferred over N::copy because if you pass an instance of A, it would have to be downcasted in order to match N::copy while no cast is required for std::copy. Here you can see that obviously std::copy is tried to be called (which gives an error because N::A lacks some typedefs).



    So, you cannot leverage a common base class for the signature of N::copy. The one and only reason I used one in my solution was to avoid duplicate code (having to declare the friend function in every iterator class). My ItBase does not participate in overload resolution at all.



    Note, however, if your iterators happen to have some common members (whether derived from some common base class or not is not important) that you want to use in your implementation of N::copy, you can just do that with my solution above like so:



    namespace N

    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    first.some_member();
    last.some_member();
    return d_first;

    ;

    struct A : ItBase<A> void some_member() ;
    struct B : ItBase<B> void some_member() ;
    struct C : ItBase<C> void some_member() ;



    See here how it works.




    On the same lines, if A, B, C have common behavior then it could be possible to replaced them by common template class parameterized in some way.



    namespace N

    template <class T, int I>
    struct ItCommon

    ...
    ;
    using A = ItCommon<double,2>;
    using B = ItCommon<int, 3>;
    using C = ItCommon<char, 5>;

    ...
    namespace N
    template<class T, int I, class Other>
    SomeN2 copy(ItCommon<T, I> first, ItCommon<T, I> last, Other)
    ...




    Since this (non-friend) copy function is definitely more constrained than the std::copy and because of ADL, it will have high priority when one of the arguments belongs to the N namespace. Also, being a non-friend, this copy function is an optional component.






    share|improve this answer

























    • This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

      – alfC
      Jan 29 at 14:29











    • @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

      – sebrockm
      Jan 29 at 15:14











    • Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

      – alfC
      Jan 29 at 16:04











    • BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

      – alfC
      Jan 29 at 16:08






    • 1





      @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

      – sebrockm
      Jan 30 at 9:48













    4












    4








    4







    You can declare copy() as a public friend function in your iterator classes.
    This works kind of as a replacement for partial specialization (which is impossible for functions), so that they will be preferred by overload resolution as they are more specialized:



    #include <iostream>
    #include <algorithm>
    #include <vector>

    namespace N

    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

    std::cout << "here" << std::endl;
    return d_first;


    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    return N::copy(first, last, d_first);

    ;

    struct A : ItBase<A>;
    struct B : ItBase<B>;
    struct C : ItBase<C>;


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


    int main()
    N::A a1, a2, a3;
    std::cout << "do something in N:" << std::endl;
    do_something(a1, a2, a3);

    std::vector<int> v = 1,2,3;
    std::vector<int> v2(3);
    std::cout << "do something in std:" << std::endl;
    do_something(std::begin(v), std::end(v), std::begin(v2));
    for (int i : v2)
    std::cout << i;
    std::cout << std::endl;



    See this demo to verify that it works.



    I introduced a common base class that declares the necessary friends for all of your iterators. So, instead of declaring a tag, as you tried, you just have to inherit from ItBase.



    Note: If N::copy() is supposed to work with only these iterators in N, it might not be needed anymore as these friend functions will be publicly visible in N anyway (as if they were free functions).




    Update:



    In the comments, it has been suggested, if the iterators in N have a common base class anyway, to just declare N::copy with this base class, e.g.



    namespace N

    template <class SomeN2>
    SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) ...



    Unfortunately, this would have the opposite effect of the desired one: std::copy will always be preferred over N::copy because if you pass an instance of A, it would have to be downcasted in order to match N::copy while no cast is required for std::copy. Here you can see that obviously std::copy is tried to be called (which gives an error because N::A lacks some typedefs).



    So, you cannot leverage a common base class for the signature of N::copy. The one and only reason I used one in my solution was to avoid duplicate code (having to declare the friend function in every iterator class). My ItBase does not participate in overload resolution at all.



    Note, however, if your iterators happen to have some common members (whether derived from some common base class or not is not important) that you want to use in your implementation of N::copy, you can just do that with my solution above like so:



    namespace N

    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    first.some_member();
    last.some_member();
    return d_first;

    ;

    struct A : ItBase<A> void some_member() ;
    struct B : ItBase<B> void some_member() ;
    struct C : ItBase<C> void some_member() ;



    See here how it works.




    On the same lines, if A, B, C have common behavior then it could be possible to replaced them by common template class parameterized in some way.



    namespace N

    template <class T, int I>
    struct ItCommon

    ...
    ;
    using A = ItCommon<double,2>;
    using B = ItCommon<int, 3>;
    using C = ItCommon<char, 5>;

    ...
    namespace N
    template<class T, int I, class Other>
    SomeN2 copy(ItCommon<T, I> first, ItCommon<T, I> last, Other)
    ...




    Since this (non-friend) copy function is definitely more constrained than the std::copy and because of ADL, it will have high priority when one of the arguments belongs to the N namespace. Also, being a non-friend, this copy function is an optional component.






    share|improve this answer















    You can declare copy() as a public friend function in your iterator classes.
    This works kind of as a replacement for partial specialization (which is impossible for functions), so that they will be preferred by overload resolution as they are more specialized:



    #include <iostream>
    #include <algorithm>
    #include <vector>

    namespace N

    template<class SomeN1, class SomeN2>
    SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

    std::cout << "here" << std::endl;
    return d_first;


    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    return N::copy(first, last, d_first);

    ;

    struct A : ItBase<A>;
    struct B : ItBase<B>;
    struct C : ItBase<C>;


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


    int main()
    N::A a1, a2, a3;
    std::cout << "do something in N:" << std::endl;
    do_something(a1, a2, a3);

    std::vector<int> v = 1,2,3;
    std::vector<int> v2(3);
    std::cout << "do something in std:" << std::endl;
    do_something(std::begin(v), std::end(v), std::begin(v2));
    for (int i : v2)
    std::cout << i;
    std::cout << std::endl;



    See this demo to verify that it works.



    I introduced a common base class that declares the necessary friends for all of your iterators. So, instead of declaring a tag, as you tried, you just have to inherit from ItBase.



    Note: If N::copy() is supposed to work with only these iterators in N, it might not be needed anymore as these friend functions will be publicly visible in N anyway (as if they were free functions).




    Update:



    In the comments, it has been suggested, if the iterators in N have a common base class anyway, to just declare N::copy with this base class, e.g.



    namespace N

    template <class SomeN2>
    SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) ...



    Unfortunately, this would have the opposite effect of the desired one: std::copy will always be preferred over N::copy because if you pass an instance of A, it would have to be downcasted in order to match N::copy while no cast is required for std::copy. Here you can see that obviously std::copy is tried to be called (which gives an error because N::A lacks some typedefs).



    So, you cannot leverage a common base class for the signature of N::copy. The one and only reason I used one in my solution was to avoid duplicate code (having to declare the friend function in every iterator class). My ItBase does not participate in overload resolution at all.



    Note, however, if your iterators happen to have some common members (whether derived from some common base class or not is not important) that you want to use in your implementation of N::copy, you can just do that with my solution above like so:



    namespace N

    template <class T>
    struct ItBase

    template <class SomeN2>
    friend SomeN2 copy(T first, T last, SomeN2 d_first)

    first.some_member();
    last.some_member();
    return d_first;

    ;

    struct A : ItBase<A> void some_member() ;
    struct B : ItBase<B> void some_member() ;
    struct C : ItBase<C> void some_member() ;



    See here how it works.




    On the same lines, if A, B, C have common behavior then it could be possible to replaced them by common template class parameterized in some way.



    namespace N

    template <class T, int I>
    struct ItCommon

    ...
    ;
    using A = ItCommon<double,2>;
    using B = ItCommon<int, 3>;
    using C = ItCommon<char, 5>;

    ...
    namespace N
    template<class T, int I, class Other>
    SomeN2 copy(ItCommon<T, I> first, ItCommon<T, I> last, Other)
    ...




    Since this (non-friend) copy function is definitely more constrained than the std::copy and because of ADL, it will have high priority when one of the arguments belongs to the N namespace. Also, being a non-friend, this copy function is an optional component.







    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Feb 1 at 20:01









    alfC

    5,08722960




    5,08722960










    answered Jan 29 at 11:32









    sebrockmsebrockm

    1,317219




    1,317219












    • This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

      – alfC
      Jan 29 at 14:29











    • @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

      – sebrockm
      Jan 29 at 15:14











    • Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

      – alfC
      Jan 29 at 16:04











    • BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

      – alfC
      Jan 29 at 16:08






    • 1





      @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

      – sebrockm
      Jan 30 at 9:48

















    • This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

      – alfC
      Jan 29 at 14:29











    • @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

      – sebrockm
      Jan 29 at 15:14











    • Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

      – alfC
      Jan 29 at 16:04











    • BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

      – alfC
      Jan 29 at 16:08






    • 1





      @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

      – sebrockm
      Jan 30 at 9:48
















    This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

    – alfC
    Jan 29 at 14:29





    This is an interesting solution and the friend in the base class allows have the coupling between the iterators and the algorithm declared only once. The problem with this is that the N::iterators will have to know of all possible algorithms that can implemented copy, fill, accumulate, etc.

    – alfC
    Jan 29 at 14:29













    @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

    – sebrockm
    Jan 29 at 15:14





    @alfC So you are saying that copy was just an example and actually you want to do this with several std algorithms? In that case you have to implement them anyway, so just put them into ItBase directly. Or am I misunderstanding you?

    – sebrockm
    Jan 29 at 15:14













    Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

    – alfC
    Jan 29 at 16:04





    Yes, the point is that these iterators will need to know about any special function in advance. Besides that point, this a good alternative design.

    – alfC
    Jan 29 at 16:04













    BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

    – alfC
    Jan 29 at 16:08





    BTW, I think public or private doesn't make a difference here for a friend function. friend functions seem to be always accesible (public).

    – alfC
    Jan 29 at 16:08




    1




    1





    @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

    – sebrockm
    Jan 30 at 9:48





    @alfC see my update. If I misunderstood what you mean, please update your question as well to ellaborate, as this seems to be an important detail in order to give you the answer that you are looking for

    – sebrockm
    Jan 30 at 9:48













    3














    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::copyn";


    template<class It1, class It2>
    void mycopy(It1 first, It1 second, It2 d_first)
    mycopy(first, second, d_first, decltype(tag(first))); // Discriminate by the type of It1.


    namespace N

    struct itAusing 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::mycopyn";



    int main()
    char* p = 0;
    mycopy(p, p, p); // calls std::copy

    N::itA q;
    mycopy(q, q, q); // calls N::mycopy






    share|improve this answer





























      3














      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::copyn";


      template<class It1, class It2>
      void mycopy(It1 first, It1 second, It2 d_first)
      mycopy(first, second, d_first, decltype(tag(first))); // Discriminate by the type of It1.


      namespace N

      struct itAusing 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::mycopyn";



      int main()
      char* p = 0;
      mycopy(p, p, p); // calls std::copy

      N::itA q;
      mycopy(q, q, q); // calls N::mycopy






      share|improve this answer



























        3












        3








        3







        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::copyn";


        template<class It1, class It2>
        void mycopy(It1 first, It1 second, It2 d_first)
        mycopy(first, second, d_first, decltype(tag(first))); // Discriminate by the type of It1.


        namespace N

        struct itAusing 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::mycopyn";



        int main()
        char* p = 0;
        mycopy(p, p, p); // calls std::copy

        N::itA q;
        mycopy(q, q, q); // calls N::mycopy






        share|improve this answer















        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::copyn";


        template<class It1, class It2>
        void mycopy(It1 first, It1 second, It2 d_first)
        mycopy(first, second, d_first, decltype(tag(first))); // Discriminate by the type of It1.


        namespace N

        struct itAusing 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::mycopyn";



        int main()
        char* p = 0;
        mycopy(p, p, p); // calls std::copy

        N::itA q;
        mycopy(q, q, q); // calls N::mycopy







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Jan 28 at 16:12

























        answered Jan 28 at 12:00









        Maxim EgorushkinMaxim Egorushkin

        87.7k11102186




        87.7k11102186





















            2














            This seems to fulfill your requirements:



            namespace SpecCopy 

            template <typename A, typename B, typename C>
            void copy(A &&a, B &&b, C &&c)
            std::copy(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));




            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            using namespace SpecCopy;
            copy(first, second, d_first);



            Basically, it depends on ADL. If no function found by ADL, then it will use SpecCopy::copy, which is a wrapper to std::copy.




            So, if you do:



            N::A a1, a2, a3;
            do_something(a1, a2, a3);


            Then do_something will call N::copy.




            If you do:



            std::vector<int> a1, a2;
            do_something(a1.begin(), a1.end(), a2.begin());


            Then do_something will call SpecCopy::copy, which will call std::copy.




            If you do:



            int *a1, *a2, *a3;
            do_something(a1, a2, a3);


            Then same thing happens as before: do_something will call SpecCopy::copy, which will call std::copy.






            share|improve this answer




















            • 1





              I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

              – Daniel Jour
              Jan 28 at 16:31











            • @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

              – geza
              Jan 28 at 16:58











            • @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

              – alfC
              Jan 28 at 19:03











            • @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

              – geza
              Jan 28 at 19:16












            • @alfC: I've edited my answer so you can see what I mean.

              – geza
              Jan 28 at 19:29















            2














            This seems to fulfill your requirements:



            namespace SpecCopy 

            template <typename A, typename B, typename C>
            void copy(A &&a, B &&b, C &&c)
            std::copy(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));




            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            using namespace SpecCopy;
            copy(first, second, d_first);



            Basically, it depends on ADL. If no function found by ADL, then it will use SpecCopy::copy, which is a wrapper to std::copy.




            So, if you do:



            N::A a1, a2, a3;
            do_something(a1, a2, a3);


            Then do_something will call N::copy.




            If you do:



            std::vector<int> a1, a2;
            do_something(a1.begin(), a1.end(), a2.begin());


            Then do_something will call SpecCopy::copy, which will call std::copy.




            If you do:



            int *a1, *a2, *a3;
            do_something(a1, a2, a3);


            Then same thing happens as before: do_something will call SpecCopy::copy, which will call std::copy.






            share|improve this answer




















            • 1





              I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

              – Daniel Jour
              Jan 28 at 16:31











            • @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

              – geza
              Jan 28 at 16:58











            • @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

              – alfC
              Jan 28 at 19:03











            • @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

              – geza
              Jan 28 at 19:16












            • @alfC: I've edited my answer so you can see what I mean.

              – geza
              Jan 28 at 19:29













            2












            2








            2







            This seems to fulfill your requirements:



            namespace SpecCopy 

            template <typename A, typename B, typename C>
            void copy(A &&a, B &&b, C &&c)
            std::copy(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));




            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            using namespace SpecCopy;
            copy(first, second, d_first);



            Basically, it depends on ADL. If no function found by ADL, then it will use SpecCopy::copy, which is a wrapper to std::copy.




            So, if you do:



            N::A a1, a2, a3;
            do_something(a1, a2, a3);


            Then do_something will call N::copy.




            If you do:



            std::vector<int> a1, a2;
            do_something(a1.begin(), a1.end(), a2.begin());


            Then do_something will call SpecCopy::copy, which will call std::copy.




            If you do:



            int *a1, *a2, *a3;
            do_something(a1, a2, a3);


            Then same thing happens as before: do_something will call SpecCopy::copy, which will call std::copy.






            share|improve this answer















            This seems to fulfill your requirements:



            namespace SpecCopy 

            template <typename A, typename B, typename C>
            void copy(A &&a, B &&b, C &&c)
            std::copy(std::forward<A>(a), std::forward<B>(b), std::forward<C>(c));




            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            using namespace SpecCopy;
            copy(first, second, d_first);



            Basically, it depends on ADL. If no function found by ADL, then it will use SpecCopy::copy, which is a wrapper to std::copy.




            So, if you do:



            N::A a1, a2, a3;
            do_something(a1, a2, a3);


            Then do_something will call N::copy.




            If you do:



            std::vector<int> a1, a2;
            do_something(a1.begin(), a1.end(), a2.begin());


            Then do_something will call SpecCopy::copy, which will call std::copy.




            If you do:



            int *a1, *a2, *a3;
            do_something(a1, a2, a3);


            Then same thing happens as before: do_something will call SpecCopy::copy, which will call std::copy.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 28 at 19:28

























            answered Jan 28 at 12:08









            gezageza

            13k32776




            13k32776







            • 1





              I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

              – Daniel Jour
              Jan 28 at 16:31











            • @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

              – geza
              Jan 28 at 16:58











            • @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

              – alfC
              Jan 28 at 19:03











            • @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

              – geza
              Jan 28 at 19:16












            • @alfC: I've edited my answer so you can see what I mean.

              – geza
              Jan 28 at 19:29












            • 1





              I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

              – Daniel Jour
              Jan 28 at 16:31











            • @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

              – geza
              Jan 28 at 16:58











            • @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

              – alfC
              Jan 28 at 19:03











            • @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

              – geza
              Jan 28 at 19:16












            • @alfC: I've edited my answer so you can see what I mean.

              – geza
              Jan 28 at 19:29







            1




            1





            I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

            – Daniel Jour
            Jan 28 at 16:31





            I don't think this solves the issue ... it ties the general do_something to the special code for the iterators ...

            – Daniel Jour
            Jan 28 at 16:31













            @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

            – geza
            Jan 28 at 16:58





            @DanielJour: Can you give an example or more explanation? I don't understand what you mean.

            – geza
            Jan 28 at 16:58













            @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

            – alfC
            Jan 28 at 19:03





            @DanielJour , geza, as DanielJour says, do_something will need to know about the SpecCopy library/namespace. and if you include SpecCopy with do_something then there is no customization, N::copy is never called in this way.

            – alfC
            Jan 28 at 19:03













            @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

            – geza
            Jan 28 at 19:16






            @alfC: Hmm, I thought that you want an ADL based solution. If iterator is in namespace N, and you have a copy function in namespace N, then with this solution, N::copy will be called.

            – geza
            Jan 28 at 19:16














            @alfC: I've edited my answer so you can see what I mean.

            – geza
            Jan 28 at 19:29





            @alfC: I've edited my answer so you can see what I mean.

            – geza
            Jan 28 at 19:29











            2














            In c++ 11 you could use tag dispatch. If you can make a little change to your custom iterators things will be a bit simpler to implement.



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;


            namespace N

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;


            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

            return copy_helper(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first), tag_t<SomeN1>);



            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            N::copy(first, second, d_first);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;



            First we change our custom iterators to have a tag type (maybe change the name to avoid confusion with iterator_category). tag can be any type you want, it just has to match the type you use as tag in copy_helper.



            Next, we define a type that allows us to access this tag type, or to fall back to a default type if tag doesn't exist. This will help us distinguish between our custom iterators and standard iterators and pointers. The default type I use is no_tag. The tag_t provides us with this functionality by using SFINAE and overload resolution. We call the function tag_helper(0) which has two declarations. The first one returns T::tag while the second one returns no_tag. Calling tag_helper(0) will always try to use the first version because int is a better match for 0 than long. This means we will always try to access T::tag first. However if this isn't possible (T::tag is not defined) SFINAE kicks in and skipps tag_helper(int) selecting tag_helper(long).



            Finally, we just have to implement a copy function for each tag (I called it copy_helper) and another copy function as a wrap around for convinience (I used N::copy). The wrapper function then creates the proper tag type and calls the correct helper function.



            Here is a live example.



            Edit



            If you move the code around a bit you can disconnect namespace N and rely on ADL:



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;



            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            copy_helper(std::forward<It1>(first), std::forward<It1>(second), std::forward<It2>(d_first), tag_t<It1>);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;






            share|improve this answer

























            • Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

              – alfC
              Jan 28 at 19:00











            • @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

              – Timo
              Jan 28 at 19:38











            • @alfC I edited my answer to rely on ADL.

              – Timo
              Jan 28 at 19:49











            • The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

              – alfC
              Jan 28 at 19:58















            2














            In c++ 11 you could use tag dispatch. If you can make a little change to your custom iterators things will be a bit simpler to implement.



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;


            namespace N

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;


            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

            return copy_helper(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first), tag_t<SomeN1>);



            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            N::copy(first, second, d_first);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;



            First we change our custom iterators to have a tag type (maybe change the name to avoid confusion with iterator_category). tag can be any type you want, it just has to match the type you use as tag in copy_helper.



            Next, we define a type that allows us to access this tag type, or to fall back to a default type if tag doesn't exist. This will help us distinguish between our custom iterators and standard iterators and pointers. The default type I use is no_tag. The tag_t provides us with this functionality by using SFINAE and overload resolution. We call the function tag_helper(0) which has two declarations. The first one returns T::tag while the second one returns no_tag. Calling tag_helper(0) will always try to use the first version because int is a better match for 0 than long. This means we will always try to access T::tag first. However if this isn't possible (T::tag is not defined) SFINAE kicks in and skipps tag_helper(int) selecting tag_helper(long).



            Finally, we just have to implement a copy function for each tag (I called it copy_helper) and another copy function as a wrap around for convinience (I used N::copy). The wrapper function then creates the proper tag type and calls the correct helper function.



            Here is a live example.



            Edit



            If you move the code around a bit you can disconnect namespace N and rely on ADL:



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;



            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            copy_helper(std::forward<It1>(first), std::forward<It1>(second), std::forward<It2>(d_first), tag_t<It1>);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;






            share|improve this answer

























            • Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

              – alfC
              Jan 28 at 19:00











            • @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

              – Timo
              Jan 28 at 19:38











            • @alfC I edited my answer to rely on ADL.

              – Timo
              Jan 28 at 19:49











            • The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

              – alfC
              Jan 28 at 19:58













            2












            2








            2







            In c++ 11 you could use tag dispatch. If you can make a little change to your custom iterators things will be a bit simpler to implement.



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;


            namespace N

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;


            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

            return copy_helper(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first), tag_t<SomeN1>);



            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            N::copy(first, second, d_first);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;



            First we change our custom iterators to have a tag type (maybe change the name to avoid confusion with iterator_category). tag can be any type you want, it just has to match the type you use as tag in copy_helper.



            Next, we define a type that allows us to access this tag type, or to fall back to a default type if tag doesn't exist. This will help us distinguish between our custom iterators and standard iterators and pointers. The default type I use is no_tag. The tag_t provides us with this functionality by using SFINAE and overload resolution. We call the function tag_helper(0) which has two declarations. The first one returns T::tag while the second one returns no_tag. Calling tag_helper(0) will always try to use the first version because int is a better match for 0 than long. This means we will always try to access T::tag first. However if this isn't possible (T::tag is not defined) SFINAE kicks in and skipps tag_helper(int) selecting tag_helper(long).



            Finally, we just have to implement a copy function for each tag (I called it copy_helper) and another copy function as a wrap around for convinience (I used N::copy). The wrapper function then creates the proper tag type and calls the correct helper function.



            Here is a live example.



            Edit



            If you move the code around a bit you can disconnect namespace N and rely on ADL:



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;



            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            copy_helper(std::forward<It1>(first), std::forward<It1>(second), std::forward<It2>(d_first), tag_t<It1>);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;






            share|improve this answer















            In c++ 11 you could use tag dispatch. If you can make a little change to your custom iterators things will be a bit simpler to implement.



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;


            namespace N

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;


            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first)

            return copy_helper(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first), tag_t<SomeN1>);



            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            N::copy(first, second, d_first);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;



            First we change our custom iterators to have a tag type (maybe change the name to avoid confusion with iterator_category). tag can be any type you want, it just has to match the type you use as tag in copy_helper.



            Next, we define a type that allows us to access this tag type, or to fall back to a default type if tag doesn't exist. This will help us distinguish between our custom iterators and standard iterators and pointers. The default type I use is no_tag. The tag_t provides us with this functionality by using SFINAE and overload resolution. We call the function tag_helper(0) which has two declarations. The first one returns T::tag while the second one returns no_tag. Calling tag_helper(0) will always try to use the first version because int is a better match for 0 than long. This means we will always try to access T::tag first. However if this isn't possible (T::tag is not defined) SFINAE kicks in and skipps tag_helper(int) selecting tag_helper(long).



            Finally, we just have to implement a copy function for each tag (I called it copy_helper) and another copy function as a wrap around for convinience (I used N::copy). The wrapper function then creates the proper tag type and calls the correct helper function.



            Here is a live example.



            Edit



            If you move the code around a bit you can disconnect namespace N and rely on ADL:



            #include <iostream>
            #include <algorithm>
            #include <vector>
            #include <type_traits>

            // indicates that the type doesn't have a tag type (like pointers and standard iterators)
            struct no_tag;

            namespace detail

            template <typename T>
            auto tag_helper(int) -> typename T::tag;

            template <typename>
            auto tag_helper(long) -> no_tag;


            // get T::tag or no_tag if T::tag isn't defined.
            template <typename T>
            using tag_t = decltype(detail::tag_helper<T>(0));

            namespace N

            struct my_iterator_tag ;
            struct A using tag = my_iterator_tag; ;
            struct B using tag = my_iterator_tag; ;
            struct C using tag = my_iterator_tag; ;

            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, my_iterator_tag)

            // your custom copy
            std::cout << "custom copy functionn";
            return ;



            template<class SomeN1, class SomeN2>
            SomeN2 copy_helper(SomeN1 first, SomeN1 last, SomeN2 d_first, no_tag)

            std::cout << "calling std::copyn";
            return std::copy(std::forward<SomeN1>(first), std::forward<SomeN1>(last), std::forward<SomeN2>(d_first));


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)

            copy_helper(std::forward<It1>(first), std::forward<It1>(second), std::forward<It2>(d_first), tag_t<It1>);


            int main()

            N::A a1, a2, a3;
            std::cout << "using custom iterator: ";
            do_something(a1, a2, a3);

            std::cout << "using vector iterator: ";
            std::vector<int> v;
            do_something(std::begin(v), std::end(v), std::begin(v));

            std::cout << "using pointer: ";
            int* ptr = new int[10];
            do_something(ptr, ptr + 5, ptr);

            return 0;







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 28 at 19:48

























            answered Jan 28 at 13:56









            TimoTimo

            1,5441626




            1,5441626












            • Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

              – alfC
              Jan 28 at 19:00











            • @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

              – Timo
              Jan 28 at 19:38











            • @alfC I edited my answer to rely on ADL.

              – Timo
              Jan 28 at 19:49











            • The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

              – alfC
              Jan 28 at 19:58

















            • Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

              – alfC
              Jan 28 at 19:00











            • @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

              – Timo
              Jan 28 at 19:38











            • @alfC I edited my answer to rely on ADL.

              – Timo
              Jan 28 at 19:49











            • The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

              – alfC
              Jan 28 at 19:58
















            Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

            – alfC
            Jan 28 at 19:00





            Thank you, but do_something will need to know about the N namespace, which might be in a disconnected library.

            – alfC
            Jan 28 at 19:00













            @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

            – Timo
            Jan 28 at 19:38





            @alfC Well you could also move the code from copy directly to do_something and include the copy_helper with the no_tag tag in the same library. Then you can rely on ADL again. Your disconnected library has to implement the copy_helper with its according tag.

            – Timo
            Jan 28 at 19:38













            @alfC I edited my answer to rely on ADL.

            – Timo
            Jan 28 at 19:49





            @alfC I edited my answer to rely on ADL.

            – Timo
            Jan 28 at 19:49













            The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

            – alfC
            Jan 28 at 19:58





            The Edit is the closest to an answer to the question so far. Note aside, I think the forward<It1> is useless unless you pass arguments as It1&& first.

            – alfC
            Jan 28 at 19:58











            1














            OK, building on @paler123, but without checking for an existing type, but checking if It1 is a pointer instead:



            namespace N
            struct A;
            struct B;
            struct C;


            namespace N
            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1, SomeN1, SomeN2 c)
            std::cout << "here" << std::endl;
            return c;


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            if constexpr (std::is_pointer_v<It1>)
            std::copy(first, second, d_first);

            else

            copy(first, second, d_first);




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

            int* b1, *b2, *b3;

            do_something(b1, b2, b3);



            Still C++17, but in the case of pointers, we go through the explicit std::copy otherwise, we rely on ADL.



            In general, your issue is a design problem. You want to use std::copy for all cases, except for objects from N, and in that case, you hope that ADL will work. But as you forced std::copy, you remove the option for proper ADL. You can't have everything and you have to redesign your code.






            share|improve this answer

























            • Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

              – alfC
              Jan 28 at 11:52











            • Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

              – Matthieu Brucher
              Jan 28 at 11:55















            1














            OK, building on @paler123, but without checking for an existing type, but checking if It1 is a pointer instead:



            namespace N
            struct A;
            struct B;
            struct C;


            namespace N
            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1, SomeN1, SomeN2 c)
            std::cout << "here" << std::endl;
            return c;


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            if constexpr (std::is_pointer_v<It1>)
            std::copy(first, second, d_first);

            else

            copy(first, second, d_first);




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

            int* b1, *b2, *b3;

            do_something(b1, b2, b3);



            Still C++17, but in the case of pointers, we go through the explicit std::copy otherwise, we rely on ADL.



            In general, your issue is a design problem. You want to use std::copy for all cases, except for objects from N, and in that case, you hope that ADL will work. But as you forced std::copy, you remove the option for proper ADL. You can't have everything and you have to redesign your code.






            share|improve this answer

























            • Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

              – alfC
              Jan 28 at 11:52











            • Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

              – Matthieu Brucher
              Jan 28 at 11:55













            1












            1








            1







            OK, building on @paler123, but without checking for an existing type, but checking if It1 is a pointer instead:



            namespace N
            struct A;
            struct B;
            struct C;


            namespace N
            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1, SomeN1, SomeN2 c)
            std::cout << "here" << std::endl;
            return c;


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            if constexpr (std::is_pointer_v<It1>)
            std::copy(first, second, d_first);

            else

            copy(first, second, d_first);




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

            int* b1, *b2, *b3;

            do_something(b1, b2, b3);



            Still C++17, but in the case of pointers, we go through the explicit std::copy otherwise, we rely on ADL.



            In general, your issue is a design problem. You want to use std::copy for all cases, except for objects from N, and in that case, you hope that ADL will work. But as you forced std::copy, you remove the option for proper ADL. You can't have everything and you have to redesign your code.






            share|improve this answer















            OK, building on @paler123, but without checking for an existing type, but checking if It1 is a pointer instead:



            namespace N
            struct A;
            struct B;
            struct C;


            namespace N
            template<class SomeN1, class SomeN2>
            SomeN2 copy(SomeN1, SomeN1, SomeN2 c)
            std::cout << "here" << std::endl;
            return c;


            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            if constexpr (std::is_pointer_v<It1>)
            std::copy(first, second, d_first);

            else

            copy(first, second, d_first);




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

            int* b1, *b2, *b3;

            do_something(b1, b2, b3);



            Still C++17, but in the case of pointers, we go through the explicit std::copy otherwise, we rely on ADL.



            In general, your issue is a design problem. You want to use std::copy for all cases, except for objects from N, and in that case, you hope that ADL will work. But as you forced std::copy, you remove the option for proper ADL. You can't have everything and you have to redesign your code.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 28 at 11:56

























            answered Jan 28 at 11:51









            Matthieu BrucherMatthieu Brucher

            15.8k32141




            15.8k32141












            • Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

              – alfC
              Jan 28 at 11:52











            • Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

              – Matthieu Brucher
              Jan 28 at 11:55

















            • Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

              – alfC
              Jan 28 at 11:52











            • Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

              – Matthieu Brucher
              Jan 28 at 11:55
















            Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

            – alfC
            Jan 28 at 11:52





            Thanks for the option. Pointer types are just an example, other (non-std iterators) will not work now. In other words this forces all iterators and pointer-like iterators to implement copy for them, even if std::copy would be fine for them.

            – alfC
            Jan 28 at 11:52













            Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

            – Matthieu Brucher
            Jan 28 at 11:55





            Yes, that's the problem, I agree. The problem you have, once again, is a design problem. You want to try to rely on ADL in some cases, but not in others. Not going to work.

            – Matthieu Brucher
            Jan 28 at 11:55











            1














            (These notes are now integrated in my edit to @sebrockm's answer)




            For discussion I will write an answer to my own question with an alternative option.



            It is not very nice because it needs to wrap all the N:: classes in another template class (called wrap here). The good thing is that do_something nor the N classes need to know about the special N::copy. The price is that the main caller has to explicitly wrap the N:: classes which is ugly but which is fine from the point of view of coupling because this is the only code that should know about the whole system.



            #include <iostream>
            #include <algorithm>
            #include <vector>

            namespace N
            struct A;
            struct B;
            struct C;


            namespace N

            template<class S> struct wrap : S;

            template<class SomeN1, class SomeN2>
            SomeN2 copy(wrap<SomeN1> first, wrap<SomeN1> last, wrap<SomeN2> d_first)

            std::cout << "here" << std::endl;
            return d_first;



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


            int main()
            N::wrap<N::A> a1, a2, a3;
            std::cout << "do something in N:" << std::endl;
            do_something(a1, a2, a3);

            std::vector<int> v = 1,2,3;
            std::vector<int> v2(3);
            std::cout << "do something in std:" << std::endl;
            do_something(std::begin(v), std::end(v), std::begin(v2));
            for (int i : v2)
            std::cout << i;
            std::cout << std::endl;






            share|improve this answer

























            • That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

              – Daniel Jour
              Jan 30 at 13:13















            1














            (These notes are now integrated in my edit to @sebrockm's answer)




            For discussion I will write an answer to my own question with an alternative option.



            It is not very nice because it needs to wrap all the N:: classes in another template class (called wrap here). The good thing is that do_something nor the N classes need to know about the special N::copy. The price is that the main caller has to explicitly wrap the N:: classes which is ugly but which is fine from the point of view of coupling because this is the only code that should know about the whole system.



            #include <iostream>
            #include <algorithm>
            #include <vector>

            namespace N
            struct A;
            struct B;
            struct C;


            namespace N

            template<class S> struct wrap : S;

            template<class SomeN1, class SomeN2>
            SomeN2 copy(wrap<SomeN1> first, wrap<SomeN1> last, wrap<SomeN2> d_first)

            std::cout << "here" << std::endl;
            return d_first;



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


            int main()
            N::wrap<N::A> a1, a2, a3;
            std::cout << "do something in N:" << std::endl;
            do_something(a1, a2, a3);

            std::vector<int> v = 1,2,3;
            std::vector<int> v2(3);
            std::cout << "do something in std:" << std::endl;
            do_something(std::begin(v), std::end(v), std::begin(v2));
            for (int i : v2)
            std::cout << i;
            std::cout << std::endl;






            share|improve this answer

























            • That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

              – Daniel Jour
              Jan 30 at 13:13













            1












            1








            1







            (These notes are now integrated in my edit to @sebrockm's answer)




            For discussion I will write an answer to my own question with an alternative option.



            It is not very nice because it needs to wrap all the N:: classes in another template class (called wrap here). The good thing is that do_something nor the N classes need to know about the special N::copy. The price is that the main caller has to explicitly wrap the N:: classes which is ugly but which is fine from the point of view of coupling because this is the only code that should know about the whole system.



            #include <iostream>
            #include <algorithm>
            #include <vector>

            namespace N
            struct A;
            struct B;
            struct C;


            namespace N

            template<class S> struct wrap : S;

            template<class SomeN1, class SomeN2>
            SomeN2 copy(wrap<SomeN1> first, wrap<SomeN1> last, wrap<SomeN2> d_first)

            std::cout << "here" << std::endl;
            return d_first;



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


            int main()
            N::wrap<N::A> a1, a2, a3;
            std::cout << "do something in N:" << std::endl;
            do_something(a1, a2, a3);

            std::vector<int> v = 1,2,3;
            std::vector<int> v2(3);
            std::cout << "do something in std:" << std::endl;
            do_something(std::begin(v), std::end(v), std::begin(v2));
            for (int i : v2)
            std::cout << i;
            std::cout << std::endl;






            share|improve this answer















            (These notes are now integrated in my edit to @sebrockm's answer)




            For discussion I will write an answer to my own question with an alternative option.



            It is not very nice because it needs to wrap all the N:: classes in another template class (called wrap here). The good thing is that do_something nor the N classes need to know about the special N::copy. The price is that the main caller has to explicitly wrap the N:: classes which is ugly but which is fine from the point of view of coupling because this is the only code that should know about the whole system.



            #include <iostream>
            #include <algorithm>
            #include <vector>

            namespace N
            struct A;
            struct B;
            struct C;


            namespace N

            template<class S> struct wrap : S;

            template<class SomeN1, class SomeN2>
            SomeN2 copy(wrap<SomeN1> first, wrap<SomeN1> last, wrap<SomeN2> d_first)

            std::cout << "here" << std::endl;
            return d_first;



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


            int main()
            N::wrap<N::A> a1, a2, a3;
            std::cout << "do something in N:" << std::endl;
            do_something(a1, a2, a3);

            std::vector<int> v = 1,2,3;
            std::vector<int> v2(3);
            std::cout << "do something in std:" << std::endl;
            do_something(std::begin(v), std::end(v), std::begin(v2));
            for (int i : v2)
            std::cout << i;
            std::cout << std::endl;







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Feb 3 at 5:44

























            answered Jan 29 at 16:21









            alfCalfC

            5,08722960




            5,08722960












            • That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

              – Daniel Jour
              Jan 30 at 13:13

















            • That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

              – Daniel Jour
              Jan 30 at 13:13
















            That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

            – Daniel Jour
            Jan 30 at 13:13





            That or the approach with the friend function is probably the best You can get; there aren't any more rules for ADL best viable candidate selection that one could leverage.

            – Daniel Jour
            Jan 30 at 13:13











            -2














            Suggest you have a look at the very powerful new Boost.HOF library.



            This function does exactly what you want:



            #include <boost/hof.hpp>

            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            namespace hof = boost::hof;

            auto my_copy = hof::first_of(
            (auto first, auto second, auto d_first) -> decltype(N::copy(first, second, d_first))

            return N::copy(first, second, d_first);
            ,
            (auto first, auto second, auto d_first) -> decltype(std::copy(first, second, d_first))

            return std::copy(first, second, d_first);
            );
            my_copy(first, second, d_first);



            hof::first_of will select the first lambda whose return type is deduced to be the result type of a legal expression.






            share|improve this answer




















            • 1





              This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

              – alfC
              Jan 28 at 20:18











            • @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

              – Richard Hodges
              Jan 29 at 0:20















            -2














            Suggest you have a look at the very powerful new Boost.HOF library.



            This function does exactly what you want:



            #include <boost/hof.hpp>

            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            namespace hof = boost::hof;

            auto my_copy = hof::first_of(
            (auto first, auto second, auto d_first) -> decltype(N::copy(first, second, d_first))

            return N::copy(first, second, d_first);
            ,
            (auto first, auto second, auto d_first) -> decltype(std::copy(first, second, d_first))

            return std::copy(first, second, d_first);
            );
            my_copy(first, second, d_first);



            hof::first_of will select the first lambda whose return type is deduced to be the result type of a legal expression.






            share|improve this answer




















            • 1





              This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

              – alfC
              Jan 28 at 20:18











            • @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

              – Richard Hodges
              Jan 29 at 0:20













            -2












            -2








            -2







            Suggest you have a look at the very powerful new Boost.HOF library.



            This function does exactly what you want:



            #include <boost/hof.hpp>

            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            namespace hof = boost::hof;

            auto my_copy = hof::first_of(
            (auto first, auto second, auto d_first) -> decltype(N::copy(first, second, d_first))

            return N::copy(first, second, d_first);
            ,
            (auto first, auto second, auto d_first) -> decltype(std::copy(first, second, d_first))

            return std::copy(first, second, d_first);
            );
            my_copy(first, second, d_first);



            hof::first_of will select the first lambda whose return type is deduced to be the result type of a legal expression.






            share|improve this answer















            Suggest you have a look at the very powerful new Boost.HOF library.



            This function does exactly what you want:



            #include <boost/hof.hpp>

            template<class It1, class It2>
            void do_something(It1 first, It1 second, It2 d_first)
            namespace hof = boost::hof;

            auto my_copy = hof::first_of(
            (auto first, auto second, auto d_first) -> decltype(N::copy(first, second, d_first))

            return N::copy(first, second, d_first);
            ,
            (auto first, auto second, auto d_first) -> decltype(std::copy(first, second, d_first))

            return std::copy(first, second, d_first);
            );
            my_copy(first, second, d_first);



            hof::first_of will select the first lambda whose return type is deduced to be the result type of a legal expression.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Jan 28 at 20:00









            alfC

            5,08722960




            5,08722960










            answered Jan 28 at 12:26









            Richard HodgesRichard Hodges

            56.1k658101




            56.1k658101







            • 1





              This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

              – alfC
              Jan 28 at 20:18











            • @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

              – Richard Hodges
              Jan 29 at 0:20












            • 1





              This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

              – alfC
              Jan 28 at 20:18











            • @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

              – Richard Hodges
              Jan 29 at 0:20







            1




            1





            This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

            – alfC
            Jan 28 at 20:18





            This looks like an interesting library. However the problem is that do_something still needs to know about the library/namespace N.

            – alfC
            Jan 28 at 20:18













            @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

            – Richard Hodges
            Jan 29 at 0:20





            @alfC I see. It wasn't clear to me that you're after a general solution for calling copy.

            – Richard Hodges
            Jan 29 at 0:20

















            draft saved

            draft discarded
















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid


            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.

            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54400763%2fhow-to-write-a-standard-like-function-that-has-high-overload-priority%23new-answer', 'question_page');

            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown






            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?