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 itA{using trait = void;};
struct itB{using trait = void;};
struct itC{using trait = void;};
}
An I want to overload copy for these iterators in this namespace. Naturally I would do:
namespace N{
template<class SomeN1, class SomeN2>
SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
std::cout << "here" << std::endl;
}
}
However when I call do_something
with N::A
, N::B
or N::C
argument I get "ambiguous call to copy" even though these are in the same namespace as N::copy
.
Is there a way to win over std::copy
in the context of the original function above?
I though that if I put constrains over the template arguments then N::copy
would be preferred.
namespace N{
template<class SomeN1, class SomeN2, typename = typename SomeN1::trait>
SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
std::cout << "here" << std::endl;
}
}
but it doesn't help.
What other workarounds can I try for the generic call to copy to prefer to a copy in the namespace of arguments rather than std::copy
.
Complete code:
#include<iostream>
#include<algorithm>
namespace N{
struct A{};
struct B{};
struct C{};
}
namespace N{
template<class SomeN1, class SomeN2>
SomeN2 copy(SomeN1 first, SomeN1 last, SomeN2 d_first){
std::cout << "here" << std::endl;
}
}
template<class It1, class It2>
void do_something(It1 first, It1 second, It2 d_first){
using std::copy;
copy(first, second, d_first); // ambiguous call when It is from namespace N (both `std::copy` and `N::copy` could work.
}
int main(){
N::A a1, a2, a3;
do_something(a1, a2, a3);
}
A typical error message is
error: call of overloaded ‘copy(N::A&, N::A&, N::A&)’ is ambiguous
Am I right to think that C++ Concepts will help here by preferring function calls with more contraints than less constraints?
using std::copy;
. – Carranzausing std::X; X(a, b, c);
) is a common way to makecopy
work with things like pointers (that don't have a namespace themselves). – ChromophoreN::copy
is also a function template that has no arguments associated with namespaceN
. Hence, it is not better thanstd::copy
for the purpose of overload resolution. – Erectionstd::copy
directly :p – Carranzastd::copy
then there is no chance the special version ofcopy
is called. The only way would be to overloadstd::copy
(in the namespacestd
) which I don't know if it is allowed. – Chromophoredo_something
, useusing namespace std; using N::copy;
? – Henchmanusing
, you make sure that you have an ambiguity with ADL for your namespace fucntions. – Carranzaauto copy(SomeN1 first, SomeN1 last, A d_first)
auto copy(SomeN1 first, SomeN1 last, B d_first)
auto copy(SomeN1 first, SomeN1 last, C d_first)
. – Chromophoredo_something
is a template function that doesn't know about the namespaceN
or the libraryN
. – Chromophorecopy
. I don't see any problems with this. – HenchmanN
enables ADL. – Erectionint*
doesn't work anymore with the class. – Carranza