我正在通过加速C ++& amp;已经遇到Ex的问题。 10.2 这些问题涉及从前一章重写中值函数,因此现在可以使用向量或内置数组调用中值。中位函数还应允许任何算术类型的容器。
我无法对下面的中位数进行两次调用 - 我收到错误消息
No matching function for call to 'median'
我从一些研究中得知,在使用模板时,应该在编译时知道Type。这可能是潜在的问题吗?有没有办法以某种方式将Type作为模板参数传递?
到目前为止,这是我的代码:
#include <iostream>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cstddef>
using namespace std;
template <class Iterator, class Type>
Type median(Iterator begin, Iterator end)
{
vector<Type> vec(begin,end);
typedef typename vector<Type>::size_type container_sz;
container_sz size = vec.size();
if (size == 0) {
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
container_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid - 1]) / 2 : vec[mid];
}
int main()
{
vector<int> grades;
for (int i = 0; i != 10; ++i){
grades.push_back(i);
}
const int int_array[] = {2, 9, 4, 6, 15};
size_t array_size = sizeof(int_array)/sizeof(*int_array);
cout << median(int_array, int_array + array_size) << endl; //error here: Semantic Issue, No matching function for call to 'median'
cout << median(grades.begin(), grades.end()) << endl; //error here: Semantic Issue, No matching function for call to 'median' "
return 0;
}
答案 0 :(得分:4)
解决此问题的最佳方法通常是使用iterator_traits
,如上所述。但是,为了回答书中的特定问题10.2(不假设Iterator_trait
知识),可以按如下方式进行:
- 注意类类型必须首先列出,而不是类Iterator。此外,必须调用median<int>(grades.begin(), grades.end())
而不是median(grades.begin(), grades.end())
#include <iostream>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include <cstddef>
using namespace std;
template <class Type, class Iterator> //the order allows the second template parameter type to be deduced (Iterator)
Type median(Iterator begin, Iterator end) //while requiring you still provide the first type
{
vector<Type> vec(begin,end);
//typedef typename vector<Type>::size_type container_sz;
//container_sz size = vec.size()
auto size = vec.size();
if (size == 0) {
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
//container_sz mid = size/2
auto mid = size/2;
Type ret = size % 2 == 0 ? (vec[mid] + vec[mid - 1]) / 2 : vec[mid];
return ret;
}
int main()
{
vector<int> grades = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
const int int_array[] = {2, 9, 4, 6, 15};
size_t array_size = sizeof(int_array)/sizeof(*int_array);
cout << median<int>(int_array, int_array + array_size) << endl; //must provide int here, in order to give the template the return type at compile time
cout << median<int>(grades.begin(), grades.end()) << endl;
return 0;
}
答案 1 :(得分:3)
您的错误源于Type
的扣除,这是所提供的参数无法实现的。您可以使用标准库类iterator_traits
执行此操作,如下所示:
template <
class Iterator,
class Type = typename std::iterator_traits<Iterator>::value_type>
Type median(Iterator begin, Iterator end)
{
vector<Type> vec(begin,end);
typedef typename vector<Type>::size_type container_sz;
container_sz size = vec.size();
if (size == 0) {
throw domain_error("median of an empty vector");
}
sort(vec.begin(), vec.end());
container_sz mid = size/2;
return size % 2 == 0 ? (vec[mid] + vec[mid - 1]) / 2 : vec[mid];
}
类iterator_traits
剖析提供的迭代器类型,以确定实际迭代的内容(稍微复杂一点,但这是一个不错的总结)。有关其工作原理的更多信息,请参阅class iterator_traits
的文档。它是确定迭代器值类型的最便捷机制。
注意:为了确保没有意外绕过默认模板参数Type
声明,您也可以这样做:
template <class Iterator>
typename std::iterator_traits<Iterator>::value_type median(Iterator begin, Iterator end)
{
if (begin == end)
throw domain_error("median of an empty vector");
typedef typename std::iterator_traits<Iterator>::value_type Type;
std::vector<Type> vec(begin,end);
sort(vec.begin(), vec.end());
typename std::vector<Type>::size_type mid = vec.size()/2;
return vec.size() % 2 == 0 ? (vec[mid] + vec[mid - 1]) / 2 : vec[mid];
}
它有点密集,抛出大部分中间的东西,但是如果你盯着它足够长的时间你会理解它是如何工作的,它会减少你的模板参数列表只使用你真正关心的一件事; Iterator
类型,这是由您提供给函数的参数所简单推导的。