2016-11-21 42 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

相关问题