【发布时间】:2017-11-06 10:04:25
【问题描述】:
我有一个模板化的双向迭代器。我不想让它随机访问,因为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 命名空间函数不允许这样做。
【问题讨论】:
-
啊,不能部分特化模板成员函数。并且不能超载它,就像你之前问的那样。难点。
-
为什么不将
distance函数与模板化迭代器放在同一个命名空间中,并通过对distance的非限定调用来依赖 ADL? -
@MassimilianoJanes - 你的意思是标准算法将重新创建
std::distance的逻辑而不是使用它?当然,标准的干字允许这样做,但真的吗? -
@Szabolcs:这仍然是个好主意。你可能对“不被自己以外的人使用”有点悲观。您面临的问题(
std::中没有重载)是众所周知的,标准解决方案是使用using std::foo; foo(arg1, arg2)。首选 ADL,回退到std::foo。 -
根据 [global.functions]/4,除非另有说明,否则标准库不会对非运算符函数进行启用 ADL 的调用。
标签: c++ templates template-specialization