Вы можете объявить copy()
как публичную функцию друга в ваших классах итераторов.Это работает как замена частичной специализации (что невозможно для функций), так что для них предпочтительнее разрешение перегрузки, поскольку они более специализированы:
#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;
}
См. это демо чтобы убедиться, что это работает.
Я ввел общий базовый класс, который объявляет необходимых друзей для всех ваших итераторов.Таким образом, вместо объявления тега, как вы пытались, вам просто нужно наследовать от ItBase
.
Примечание: если N::copy()
должен работать только с этими итераторами в N
, он может непонадобиться больше, так как эти функции-друзья все равно будут публично видны в N
(как если бы они были свободными функциями).
Обновление:
В комментариях было предложеноесли итераторы в N
в любом случае имеют общий базовый класс, просто объявить N::copy
с этим базовым классом, например,
namespace N
{
template <class SomeN2>
SomeN2 copy(ItBase first, ItBase last, SomeN2 d_first) { ... }
}
К сожалению, это будет иметь эффект, противоположный желаемому: std::copy
всегда будет предпочтительнее, чем N::copy
, потому что если вы передадите экземпляр A
, он должен быть понижен, чтобы соответствовать N::copy
, в то время как для std::copy
не требуется приведение. Здесь вы можете видеть, что, очевидно, std::copy
пытаются вызвать (что выдает ошибку, потому что N::A
не имеет некоторых typedefs).
Таким образом, вы не можете использовать общий базовый класс дляподпись N::copy
.Единственная причина, по которой я использовал ее в своем решении, заключалась в том, чтобы избежать дублирования кода (необходимость объявлять функцию друга в каждом классе итераторов).Мой ItBase
вообще не участвует в разрешении перегрузки.
Обратите внимание, однако, если у ваших итераторов есть некоторые общие члены (независимо от того, являются ли они производными от некоторого общего базового класса или нет, это не важно), которые вы хотите использоватьиспользовать в своей реализации N::copy
, вы можете просто сделать это с моим решением выше, например так:
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() {} };
}
См. здесь как это работает.
В тех же строках, если A, B, C имеют общее поведение, можно было бы заменить их на общий шаблонный класс, параметризованный каким-либо образом.
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){
...
}
}
Поскольку это (не в друзьях) * 1054Функция * определенно более ограничена, чем std::copy
, и из-за ADL она будет иметь высокий приоритет, когда один из аргументов принадлежит пространству имен N
.Кроме того, функция copy
, будучи не другом, является необязательным компонентом.