简体   繁体   English

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

[英]I'm having problems relating to template arguments

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;
}

I'm having trouble with class T, the return type for the median function. 我在T类(中位数函数的返回类型)上遇到麻烦。 If I take it out and turn T into int, it seems to work but lessens the meaning of using templates. 如果我将其取出并将T转换为int,它似乎可以工作,但会减少使用模板的含义。 Help! 救命!

Switch the order of template parameters: 切换模板参数的顺序:

template <class T, class RandomIterator> 
T median(RandomIterator b, RandomIterator e)

This way you need to pass only the type of T at the call: 这样,您只需在通话时传递T类型:

median<int>(it1, it2);

Or, better yet, get rid of T altogether: 或者,更好的是,完全摆脱T:

template <class RandomIterator> 
auto median(RandomIterator b, RandomIterator e) -> auto(*b) 

To answer your actual question, the issue with templates is that the compiler needs to be able to figure out what the type T is just from the function call. 为了回答您的实际问题,模板的问题是编译器需要能够仅从函数调用中找出类型T是什么。 It can't do this because T is never used directly, and certainly not in the function signature (which excludes the return type). 它之所以不能这样做,是因为T从不直接使用,当然也不在函数签名(不包括返回类型)中使用。

Slight improvement 轻微改善

One approach is to explicitly state it when calling, eg median<std::vector<double>::iterator, double>(mvvec.begin(), myvec.end()); 一种方法是在调用时显式声明它,例如median<std::vector<double>::iterator, double>(mvvec.begin(), myvec.end()); but that is rather unwieldy. 但这相当笨拙。 A better option would be to swap the order of RandomIterator and T in the template declaration so that you can just specify the return type: median<double>(myvec.begin(), myvec.end()); 更好的选择是在模板声明中交换RandomIteratorT的顺序,以便您可以仅指定返回类型: median<double>(myvec.begin(), myvec.end());

Better improvement 更好的改善

However, in C++11 and later you can do better. 但是,在C ++ 11和更高版本中,您可以做得更好。 Drop the class T in the template and use auto, specifying the iterator's value_type if needed: auto median(RandomIterator b, RandomIterator e) -> decltype(*b) You may find the decltype is not necessary. class T放到模板中,并使用auto,并在需要时指定迭代器的value_type: auto median(RandomIterator b, RandomIterator e) -> decltype(*b)您可能会发现decltype不必要。 However you also need to be sure whether you want to return aa value or a reference - there are pros and cons each way so I can't decide for you. 但是,您还需要确定是否要返回一个值或一个引用-每种方法都有优缺点,所以我无法为您决定。

Best approach 最佳方法

However, your function is unusual in that it both operates on a range (pair of iterators) yet returns a value. 但是,您的函数与众不同之处在于,它们都在一个范围(一对迭代器)上运行,但返回一个值。 Most STL algorithms return an iterator, because they can't be sure if it is safe to dereference it or not. 大多数STL算法都返回一个迭代器,因为它们不确定取消引用是否安全。 Suppose you passed begin() and end() from an empty vector, for example. 例如,假设您从一个空向量传递了begin()和end()。 By returning an iterator the caller makes the decision to dereference (or not). 通过返回迭代器,调用者可以决定取消引用。 This also solves the problem of returning a value or reference. 这也解决了返回值或引用的问题。 The call is then just median(mvvec.begin(), myvec.end()); 然后,该调用只是median(mvvec.begin(), myvec.end()); - add a deference if you need to. -如果需要,请加一个参考。

Algorithm refinement 算法细化

b and e must be random access iterators since you are calling to std::sort . be必须是随机访问迭代器,因为您正在调用std::sort However the count is calculated inefficiently. 但是,计数计算效率很低。 Consider simply using auto count = e - b; 考虑简单地使用auto count = e - b; and auto mid = count / 2; auto mid = count / 2; Use of auto will give you the correct difference_type, which is not always the same as int. 使用auto将为您提供正确的difference_type,它并不总是与int相同。 Typically it is ptrdiff_t but good iterator code shouldn't assume even that. 通常它是ptrdiff_t,但是即使如此,良好的迭代器代码也不应假定。 If you can't use auto then typename std::iterator_traits<RandomIterator>::difference_type is the correct type to use. 如果不能使用autotypename std::iterator_traits<RandomIterator>::difference_type是正确的类型。

There is no need to specify the return type as template argument. 无需将返回类型指定为模板参数。 You can access the underlying type of an iterator using the following: 您可以使用以下方法访问迭代器的基础类型:

std::iterator_traits<RandomIterator>::value_type

If you still want to do that, then you have to specify the type of all template arguments explicitly because the compiler is not able to uniquely infer it by using the other types provided. 如果仍然要这样做,则必须显式指定所有模板参数的类型,因为编译器无法通过使用提供的其他类型来唯一地推断出它。

I would remove it altogether as in the following: 我将其完全删除,如下所示:

template <class RandomIterator>
std::iterator_traits<RandomIterator>::value_type median(RandomIterator b, RandomIterator e)

or even better using auto 甚至更好地使用自动

    template <class RandomIterator>
   auto median(RandomIterator b, RandomIterator e)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM