2017-01-09 48 views
4

我需要學習如何使用enable_if。爲此,我需要使用enable_if重新實現距離函數。我嘗試這樣做:如何正確使用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 爲此,我檢查了type_traits但找不到檢查,如果事情是一個特定的迭代器什麼。 我該如何檢查是否有一個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放入該模板中?

回答

5

可以使用型性狀std::is_same<>如下

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) { /* ... */ } 

這裏,std::enable_if_t<,>是定義一個輔助別名(因爲C++ 14)

template<bool condition, typename type = void> 
using enable_if_t = typename enable_if<condition,type>::type; 

實際上,您也可以將您的功能f()聲明爲constexpr,並直接在enable_if內使用它,即std::enable_if<f<It>(), ...>

+0

試圖使用你的解決方案給我的錯誤:'預期的類型,得到'std :: iterator_traits <_Iterator> :: iterator_category'' – Hakaishin

+0

@Hakaishin好吧,我沒有測試它。我忘了'typename'。 – Walter

+0

不知道爲什麼,但我不能編輯我以前的評論。但無論如何,這整個元編程的東西似乎只是做編程,但在這些<>中。我看到了潛在的好處,但有時我會問自己是否值得了解所有這些事情以及它們實際使用的頻率...... – Hakaishin