我有一个模板化的双向迭代器。 我不想让它随机访问,因为it += n
操作不会是恒定时间。 但是,it2 - it1
操作是恒定时间。 我想专门为这个迭代器std::distance()
,以便使用它的算法(例如std::vector::assign()
)可以利用有效的差分运算。 如果迭代器是模板,我该怎么做?
下面是一个玩具示例:
#include <iterator>
#include <iostream>
// template bidirectional iterator
template<typename T>
class iter : public std::iterator<std::bidirectional_iterator_tag, T> {
T *ptr;
public:
iter(T *ptr) : ptr(ptr) { }
iter() = default;
iter(const iter &) = default;
iter &operator = (const iter &) = default;
T *operator * () { return ptr; }
bool operator == (const iter &it) { return ptr == it.ptr; }
bool operator != (const iter &it) { return ptr != it.ptr; }
iter &operator ++ () { ++ptr; return *this; }
iter operator ++ (int) { iter tmp(*this); operator++(); return tmp; }
iter &operator -- () { --ptr; return *this; }
iter operator -- (int) { iter tmp(*this); operator--(); return tmp; }
// Would not be used for a bidirectional iterator.
// Implemented only so we can use it in std::distance() below.
ptrdiff_t operator - (const iter &it) { return ptr - it.ptr; }
};
namespace std {
// We could specialize std::distance() for iter<int> like this:
template<>
iter<int>::difference_type distance(iter<int> first, iter<int> last) {
std::cout << "my distance calledn";
return last - first;
}
// QUESTION: Can we do it in general, for iter<T> ?
}
// Just to test that everything works as intended.
int main() {
int arr[5];
iter<int> it1(&arr[0]);
iter<int> it2(&arr[5]);
std::cout << std::distance(it1, it2) << std::endl;
return 0;
}
这是重载 std 函数(如 std::d istance)是否合理
?原则上我们可以做这样的事情:
namespace std {
template<class T>
typename iter<T>::difference_type distance(iter<T> first, iter<T> last) {
std::cout << "my distance calledn";
return last - first;
}
}
但这将是std::distance()
的重载,根据标准,std
命名空间函数是不允许的。
方法是在与iter
-template相同的命名空间中定义distance
方法(在本例中为全局命名空间)。
....
typename iter::difference_type operator -(const iter &it)
{
return ptr - it.ptr;
}
}; // close template<typename T> class iter
template<typename T>
typename iter<T>::difference_type distance( iter<T> first, iter<T> last)
{
std::cout << "my distance calledn";
return last - first;
}
稍后使用 ADL,如以下示例所示:
int main()
{
int arr[5];
iter<int> it1(&arr[0]);
iter<int> it2(&arr[5]);
using std::distance;
using std::begin;
using std::end;
std::cout << distance(it1, it2) << 'n';
std::cout << "using std::distancen";
std::cout << distance(begin(arr), end(arr)) << 'n';
return 0;
}
将输出:
my distance called
5
using std::distance
5
斯科特·迈耶斯(Scott Meyers)在他的著作"有效C++",第三版,第25项中对std方法模板的部分专业化问题给出了很好的解释。