【问题标题】:Inferring a type from a dereferenced iterator in a template function从模板函数中的取消引用迭代器推断类型
【发布时间】:2016-05-15 16:58:39
【问题描述】:

我正在完成“加速 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;
}

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

没有匹配函数调用“中位数”...候选模板被忽略:无法推断模板参数“T”

据我所知,问题在于编译器无法从取消引用的迭代器中推断出“T”的类型。我想知道

A.为什么会这样?

B.有没有优雅的方法来解决这个问题?

【问题讨论】:

    标签: c++ templates pointers types


    【解决方案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) { ... }
    

    所有这一切的信息都可以从例如收集到。 this std::vector reference 告诉您向量中的 iterator 类型是 random access iterator,其中提到了 value_type 以及如何从 std::iterator_traits 找到它。

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

    【讨论】:

      【解决方案2】:

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

      解决方案:

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

      live example

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-12
        • 2019-05-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多