template <class RandomIterator, class T>
T median(RandomIterator b, RandomIterator e)
{
std::sort(b, e);
int count = 0;
for(RandomIterator ri = b; ri != e; ++ri)
++count;
int mid = count / 2;
return (count % 2 == 0) ? *(b+mid) : (*(b+mid) + *(b+mid+1)) / 2;
}
我在T类(中位数函数的返回类型)上遇到麻烦。如果我将其取出并将T转换为int,它似乎可以工作,但会减少使用模板的含义。救命!
答案 0 :(得分:2)
切换模板参数的顺序:
template <class T, class RandomIterator>
T median(RandomIterator b, RandomIterator e)
这样,您只需在通话时传递T类型:
median<int>(it1, it2);
或者更好的是,完全摆脱T:
template <class RandomIterator>
auto median(RandomIterator b, RandomIterator e) -> auto(*b)
答案 1 :(得分:1)
要回答您的实际问题,模板的问题是编译器需要能够仅从函数调用中找出类型T
是什么。之所以不能这样做,是因为T
从未直接使用过,而且肯定不在函数签名(不包括返回类型)中使用。
一种方法是在调用时明确声明它,例如median<std::vector<double>::iterator, double>(mvvec.begin(), myvec.end());
,但这相当笨拙。更好的选择是在模板声明中交换RandomIterator
和T
的顺序,这样您就可以指定返回类型:median<double>(myvec.begin(), myvec.end());
但是,在C ++ 11和更高版本中,您可以做得更好。将class T
放到模板中并使用auto,如果需要,请指定迭代器的value_type:
auto median(RandomIterator b, RandomIterator e) -> decltype(*b)
您可能会发现不需要十进制类型。但是,您还需要确定要返回值还是引用-每种方法都有优缺点,所以我无法为您做出决定。
但是,您的函数与众不同之处在于,它们都在一个范围(一对迭代器)上运行,但返回一个值。大多数STL算法都返回一个迭代器,因为它们不确定取消引用是否安全。例如,假设您从一个空向量传递了begin()和end()。通过返回迭代器,调用者可以决定取消引用。这也解决了返回值或引用的问题。这样,呼叫就是median(mvvec.begin(), myvec.end());
-如果需要,可以添加一个引用。
b
和e
必须是随机访问迭代器,因为您正在调用std::sort
。但是,计数计算效率很低。考虑简单地使用auto count = e - b;
和auto mid = count / 2;
,使用auto
将为您提供正确的difference_type,但它并不总是与int相同。通常它是ptrdiff_t,但是即使如此,良好的迭代器代码也不应假定。
如果您不能使用auto
,那么typename std::iterator_traits<RandomIterator>::difference_type
是正确的类型。
答案 2 :(得分:0)
无需将返回类型指定为模板参数。 您可以使用以下命令访问迭代器的基础类型:
std::iterator_traits<RandomIterator>::value_type
如果仍然要这样做,则必须明确指定所有模板参数的类型,因为编译器无法使用所提供的其他类型来唯一地推断出它。
我将完全删除它,如下所示:
template <class RandomIterator>
std::iterator_traits<RandomIterator>::value_type median(RandomIterator b, RandomIterator e)
或者甚至更好地使用自动
template <class RandomIterator>
auto median(RandomIterator b, RandomIterator e)