2017-11-06 8 views
9

템플릿 기반의 양방향 반복기가 있습니다. it += n 작업이 일정 시간이 아니기 때문에 랜덤 액세스를하고 싶지 않습니다. 그러나 it2 - it1 작업 일정 시간입니다. 이 반복자에 대해 std::distance()을 사용하여이를 사용하는 알고리즘 (예 : std::vector::assign())이 효율적인 차이 작업을 사용할 수 있도록하려고했습니다. 반복자가 템플릿 인 경우 을 어떻게 수행 할 수 있습니까??사용자 정의 템플릿 반복기에 대해 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; 
    } 
} 

하지만 그건 것 :


#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?

의 후속이다 : 여기

는 장난감 예제 std::distance()의 과부하 일 수 있으며는 허용되지 않습니다. 10 네임 스페이스는 표준에 따라 기능합니다.

+1

아, 부분적으로 템플릿을 전문으로 할 수 없습니다. 전자 회원 기능. 이전에 물어 본 것처럼 그것을 오버로드 할 수 없습니다. 터프한 지점. – StoryTeller

+0

@StoryTeller 이것은 단지 최적화 기회 일 뿐이므로 아마도 iter가 가장 일반적으로 사용되는 몇 가지 유형에 대한 전문화 만 제공 할 수 있습니다. – Szabolcs

+0

거리를 미리 아는 경우 벡터 :: 할당 전에 vector :: reserve를 사용할 수 없습니까? –

답변

1

distance 메서드를 iter -template (이 경우 전역 네임 스페이스)과 동일한 네임 스페이스에 정의하는 것이 올바른 방법입니다.

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 

방법 템플릿의 부분 특수화이 문제에 대한 좋은 설명이 표준이다에서이 예에서와 같이 ADL을 사용

.... 
    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; 
} 

그리고 나중에 Scott Meyers가 "Effective C++", 제 3 판, 항목 25에 제시했습니다.