我有一个模板化的双向迭代器。我不想让它随机访问,因为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 called\n";
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;
}
这是Is it reasonable to overload std functions such as std::distance?
的后续行动我们原则上可以这样做:
namespace std {
template<class T>
typename iter<T>::difference_type distance(iter<T> first, iter<T> last) {
std::cout << "my distance called\n";
return last - first;
}
}
但这将是std::distance()
的重载,根据标准,std
命名空间函数不允许这样做。
答案 0 :(得分:3)
正确的方法是在与distance
- 模板相同的命名空间中定义iter
方法(在本例中为全局命名空间)。
....
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 called\n";
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::distance\n";
std::cout << distance(begin(arr), end(arr)) << '\n';
return 0;
}
将输出:
my distance called
5
using std::distance
5
Scott Meyers在其着作“Effective C ++”第三版第25项中给出了std方法模板部分特化问题的一个很好的解释。