2016-11-21 96 views
3

參考,例如,該段從cplusplus.com爲什麼在模板函數中使用iterator_traits而不是僅使用另一個模板類型參數?

template <class InputIterator, class T> 
typename iterator_traits<InputIterator>::difference_type 
count(InputIterator first, InputIterator last, const T& val) 
{ 
    typename iterator_traits<InputIterator>::difference_type ret = 0; 
    while (first!=last) { 
     if (*first == val) 
      ++ret; 
     ++first; 
    } 
    return ret; 
} 

現在的問題是,爲什麼用在這方面iterator_traits而不是採取在另一個模板參數如下所示:

template <class InputIterator, class T, class DiffType> 
DiffType count(InputIterator first, InputIterator last, const T& val) 
{ 
    DiffType ret = 0; 
    while (first!=last) { 
     if (*first == val) 
      ++ret; 
     ++first; 
    } 
    return ret; 
} 
+3

這非常寬泛,但我會嘗試一下:迭代器特徵,並且一般情況下的特徵(如成員類型)可以很好地適用於約定。通過慣例使用「標準」特徵,一些算法和數據結構可以很好地與標準模板庫的其餘部分搭配使用,並且可以實現更好的元編程。 – AndyG

+0

另一個模板類*可以被定義,但是一旦我們完成了一次,我們不想再爲每一個不同的算法重新做它 –

+0

我可能是密集的,但你能舉一個你在想什麼的例子嗎?你最後一句話? – Quentin

回答

4

的建議你在評論中提出的建議 - 讓函數接受另一個模板參數 - 不會按照您的意圖工作。這裏有你所建議的代碼:

template <class InputIterator, class T, typename DiffType> 
DiffType count(InputIterator first, InputIterator last, const T& val) 
{ 
    DiffType ret = 0; 
    while (first!=last) { 
     if (*first == val) 
      ++ret; 
     ++first; 
    } 
    return ret; 
} 

這段代碼的問題是,這不再編譯:

std::vector<int> v = /* ... */; 
auto numElems = count(v.begin(), v.end(), 137); // <--- Error! 

這裏的問題是,爲了調用一個函數模板,每個模板參數要麼可以從參數類型中推導出來,要麼由調用者明確指定。在這裏,類型DiffType不能從參數類型推導出來(InputIteratorT類型可以從兩個參數中推斷出來,但是從簽名本身就沒有上下文),所以這個調用會因編譯器錯誤而失敗。這裏使用std::iterator_traits是一個通用模板模式,用於從迭代器類型本身提取關於迭代器的信息。

+0

那麼,DiffType至少可以是第一個模板參數。仍然不是所有的事情都可以推論,但有點更好... – Deduplicator

+0

@BoPersson哦,好點。我相信我所做的修改解決了這個問題? – templatetypedef

+0

@Deduplicator在這種情況下,您是否仍然需要明確提供差異類型? – templatetypedef