У меня проблемы с аргументами шаблона - PullRequest
0 голосов
/ 18 марта 2019
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, это, кажется, работает, но уменьшает значение использования шаблонов.Помогите! * * 1002

Ответы [ 3 ]

2 голосов
/ 18 марта 2019

Переключить порядок параметров шаблона:

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 голос
/ 18 марта 2019

Чтобы ответить на ваш реальный вопрос, проблема с шаблонами заключается в том, что компилятор должен иметь возможность выяснить, какой тип 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) Возможно, вы обнаружите, что decltype не нужен.Однако вы также должны быть уверены, хотите ли вы вернуть значение или ссылку - есть плюсы и минусы в каждом случае, поэтому я не могу решить за вас.

Лучший подход

Однако,Ваша функция необычна тем, что она работает с диапазоном (пара итераторов), но возвращает значение.Большинство алгоритмов STL возвращают итератор, потому что они не могут быть уверены, безопасно ли разыменовывать его или нет.Предположим, вы передали begin () и end (), например, из пустого вектора.Возвращая итератор, вызывающая сторона принимает решение о разыменовании (или нет).Это также решает проблему возврата значения или ссылки.В этом случае вызов просто median(mvvec.begin(), myvec.end()); - добавьте deference, если вам нужно.

Уточнение алгоритма

b и e должны быть итераторами произвольного доступа, так как вы звоните на std::sort.Однако счет рассчитывается неэффективно.Попробуйте просто использовать auto count = e - b; и auto mid = count / 2; Использование auto даст вам правильный diff_type, который не всегда совпадает с int.Обычно это ptrdiff_t, но хороший код итератора не должен предполагать даже этого.Если вы не можете использовать auto, тогда typename std::iterator_traits<RandomIterator>::difference_type - правильный тип для использования.

0 голосов
/ 18 марта 2019

Нет необходимости указывать тип возвращаемого значения в качестве аргумента шаблона. Вы можете получить доступ к базовому типу итератора, используя следующее:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...