Ich habe einen templated bidirektionalen Iterator. Ich möchte es nicht wahlfrei machen, weil die Operation it += n
keine konstante Zeit wäre. Die it2 - it1
Operation ist jedoch konstante Zeit. Ich wollte std::distance()
für diesen Iterator spezialisieren, damit Algorithmen, die ihn verwenden (wie std::vector::assign()
), die effiziente Differenzoperation verwenden können. Wie kann ich dies tun , wenn der Iterator eine Vorlage ist?Wie std :: distance() für benutzerdefinierte Vorlagen Iterator implementieren?
Hier ist ein Spielzeug Beispiel:
#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;
}
Dies ist ein Follow-up von Is it reasonable to overload std functions such as std::distance?
Wir prinzipiell so etwas tun könnte:
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;
}
}
aber das würde sei eine Überladung von std::distance()
, die fürnicht erlaubt ist 10 Namespace funktioniert nach dem Standard.
Ah, kann nicht teilweise ein Templat spezialisieren Die Mitgliedsfunktion. Und kann es nicht überladen, wie Sie zuvor gefragt haben. Starker Punkt. – StoryTeller
@StoryTeller Da dies nur eine Optimierungsmöglichkeit ist, könnte ich vielleicht nur Spezialisierungen für die wenigen Typen bereitstellen, mit denen 'iter' am häufigsten verwendet wird. – Szabolcs
Wenn du die Entfernung im Voraus kennst, kannst du nicht einfach vector :: reserve vor vector :: assign? –