2017-01-09 8 views
4

나는 enable_if를 사용하는 법을 배워야합니다. 이를 위해 나는 enable_if를 사용하여 distance 함수를 다시 구현해야합니다. 나는 type_traits을 확인하지만 뭔가 특정 반복자 경우 확인을 위해 아무것도 찾을 수 없습니다 enable_if를 올바르게 사용하는 방법은 무엇입니까?

#include <iostream> 
#include <vector> 
#include <list> 
#include <utility> 
#include <type_traits> 

template<class In> 
typename std::enable_if<!std::is_random_acces_iterator<In>::value, std::iterator_traits<In>::difference_type>::type my_distance(In begin, In end, std::input_iterator_tag dummy){ 
    typename std::iterator_traits<In>::difference_type n = 0; 
    while(begin!=end){ 
    ++begin; ++n; 
    } 
    std::cout << "STEPPING" << std::endl; 
    return n; 
} 

template<class Ran> 
typename std::enable_if<std::is_random_acces_iterator<Ran>::value, std::iterator_traits<In>::difference_type>::type my_distance(Ran begin, Ran end, std::random_access_iterator_tag dummy){ 
    std::cout << "RANDOM" << std::endl; 
    return end - begin; 
} 

template <class I> inline 
typename std::iterator_traits<I>::difference_type my_distance_wrapper(I begin, I end){ 
    typedef typename std::iterator_traits<I>::iterator_category cat; 
    return my_distance(begin, end, cat()); 
} 

int main() { 
    std::vector<int> ve; 
    std::list<int> li; 
    for(int i = 0; i < 3; i++){ 
    ve.push_back(i); 
    li.push_back(i); 
    } 
    std::cout << my_distance_wrapper(ve.begin(), ve.end()) << std::endl; 
    std::cout << my_distance_wrapper(li.begin(), li.end()) << std::endl; 
    return 0; 
} 

가 나는 비슷한 std::is_random_acces_iterator<In>::value std::is_pod<In>::value에 같은 일부 기능을 사용하여이 작업을 수행 할 수 있다고 생각 : 나는 이것을 시도했다. 뭔가 random_acces_iterator가 있는지 어떻게 확인하나요? 나는 함수 내에서 이것을 할 수 있다는 것을 알고있다 :

template<class T> 
bool f(){ 
    typedef typename std::iterator_traits<T>::iterator_category cat; 
    return std::random_access_iterator_tag == cat(); 
} 

그럼 내 질문은 기본적으로 어떻게 함수 f를 템플릿에서 하는가? 그리고 enable_if를 사용할 수 없다는 것은 내 작업의 요구 사항입니다. 그리고 SFINAE가 함수 f를 그 템플릿에 넣을 수 있다면 다른 함수를 올바르게 버릴 것이라고 생각하는 것이 맞습니까?

template<typename iterator> 
using is_random_access_iterator = 
    std::is_same<typename std::iterator_traits<iterator>::iterator_category, 
       std::random_access_iterator_tag>; 

하고 여기에 다음

template<typename iterator> 
std::enable_if_t<is_random_access_iterator<iterator>::value, 
       typename std::iterator_traits<iterator>::difference_type> 
my_distance(iterator a, iterator b) { return a-b; } 

template<typename iterator> 
std::enable_if_t<!is_random_access_iterator<iterator>::value, 
       typename std::iterator_traits<iterator>::difference_type> 
my_distance(iterator a, iterator b) { /* ... */ } 

을 다음과 같이

답변

5

당신은 std::is_same<> 유형의 특성을 사용할 수 std::enable_if_t<,>

template<bool condition, typename type = void> 
using enable_if_t = typename enable_if<condition,type>::type; 
로 (C++ 14부터) 정의 도우미 별칭입니다

실제로는 f() 함수를 constexpr으로 선언하고 enable_if, 즉 std::enable_if<f<It>(), ...>에 직접 사용할 수도 있습니다.

+0

해결책을 사용하려고하면 '예상 유형이 있습니다.'라는 메시지가 나타납니다. iterator_traits <_Iterator> :: iterator_category '' – Hakaishin

+0

@Hakaishin 괜찮습니다. 테스트하지 않았습니다. 'typename'을 잊어 버렸습니다. – Walter

+0

왜 그런지 모르지만 이전 의견을 수정할 수 없습니다. 그러나 어쨌든이 전체 메타 프로그래밍 작업은 단순히 프로그래밍 만하는 것 같지만이 내부에서는 가능합니다. 나는 잠재적 인 이익을보고 있지만 때로는 모든 것을 배우는 가치가 있고 실제로 얼마나 자주 사용되는지 스스로에게 묻습니다. – Hakaishin