我在与模板参数有关的问题

时间:2019-03-18 08:59:23

标签: c++ templates

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,它似乎可以工作,但会减少使用模板的含义。救命!

3 个答案:

答案 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());,但这相当笨拙。更好的选择是在模板声明中交换RandomIteratorT的顺序,这样您就可以指定返回类型: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());-如果需要,可以添加一个引用。

算法优化

be必须是随机访问迭代器,因为您正在调用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)