在模板函数中从解除引用的迭代器中推断类型

时间:2016-05-15 16:58:40

标签: c++ templates pointers types

我正在研究" Accelerated C ++"中的练习,我发现了一些我不了解的关于编译器如何在函数模板中推断类型的行为。在练习10-2中,我们被要求编写一个模板函数,该函数可以计算向量或内置数组中算术类型列表的中值。我偶然发现了一个这个问题的示例解决方案,它涉及一个模板函数,它计算并返回两个迭代器之间的中值容器值,即我创建了以下文件名为" median.hpp" :

#ifndef median_hpp
#define median_hpp

#include <algorithm>
#include <stdexcept>
#include <vector>

using std::domain_error;
using std::sort;
using std::vector;

template <class T, class Iterator>
T median(Iterator begin, Iterator end) {

  //check if the container is empty
  if (begin == end)
    throw domain_error("median of an empty container");

  //create a vector with the same type as the container
  //and copy the container contents into it 
  vector<T> temp;

  for ( ; begin != end; ++begin)
    temp.push_back(*begin);

  //sort the temporary vector, and compute and return the median
  sort(temp.begin(), temp.end());

  size_t mid = temp.size() / 2;

  T ret = (temp.size() % 2 == 0)
    ? (temp[mid] + temp[mid - 1]) / 2
    : temp[mid];

  return ret;
}

#endif /* median_hpp */

所以,如果我想计算一个数组和向量的中值来证明这个函数适用于两种容器类型,我会使用上面提到的模板函数:

#include <iostream>
#include <vector>
#include "median.hpp"

using std::vector;
using std::cout;
using std::cin;
using std::endl;

int main()
{

    int arr[] = {12,2,4,1,4,56,1};

    const size_t nData = sizeof(arr)/sizeof(*arr);
    vector<double> v(arr, arr + nData);

    cout << median(v.begin(),v.end()) << endl;
    cout << median(arr, arr + nData) << endl;

    return 0;
}

但是,由于我不理解的原因,我收到以下错误:

没有匹配功能可以调用&#39;中位数&#39; ...忽略候选模板:无法推断模板参数&#39; T&#39;

据我所知,问题是编译器无法推断出&#34; T&#34;来自解引用的迭代器。我想知道

一个。为什么会这样?

B中。有没有一种优雅的方法来解决这个问题?

2 个答案:

答案 0 :(得分:1)

编译器可以推断Iterator,但不推断T。那是因为oterator无法说出如何从你传递给它的任何东西推断TIterator?在未知的Iterator类型中,如果不知道T实际上是什么,您将如何知道Iterator是什么?编译器根本不知道。

但是,由于您知道Iterator是实际的迭代器类型,并且大多数迭代器都将类型别名返回到包含的类型T,您可以执行类似

的操作
template <class Iterator, class T = typename std::iterator_traits<Iterator>::value_type>
T median(Iterator begin, Iterator end) { ... }

有关所有这些的信息可以通过以下方式收集: CREATE INDEX...WITH(DROP_EXISTING=ON),它告诉您向量中的iterator类型是this std::vector reference,提及value_type以及如何从random access iterator找到它。

std::iterator_traits应该可以用于所有标准迭代器,而不仅仅是std::vector给出的随机访问迭代器。

答案 1 :(得分:1)

由于T没有median类型的参数,编译器无法推断该类型。

解决方案:

template <class Iterator, class T = typename std::iterator_traits<Iterator>::value_type>
T median(Iterator begin, Iterator end) {
    // ....
}

std::iterator_traits