Типичная подпись шаблона функции:
template<typename Iterator, typename T>
T fn(Iterator first, Iterator last, T init)
{
T result;
// ...
return result;
}
Проблема в том, когда я называю это так:
std::vector<long> data(1000,1);
fn(data.begin(), data.end(), 0);
или любым другим способом без явного вызова
fn<std::vector<long>::iterator, long>(data.begin(), data.end(),0);
тогда тип Т является int
и есть риск переполнения и плохих результатов в fn
,
Так, как я специализируюсь fn
так что призыв к
fn(data.begin(), data.end(), 0);
однозначно и приводит к T
быть установленным на Iterator::value_type
? Выбор
template<Iterator>
typename iterator_traits<Iterator>::value_type fn(Iterator first, Iterator last, typename iterator_traits<Iterator>::value_type init)
{
//...
}
приводит к неоднозначной ошибке вызова из g ++ / clang ++.
РЕДАКТИРОВАТЬ:
Теперь я вижу свою ошибку, и приведенный выше код работает с предложением @Lightness Races ниже. Спасибо за помощь.
Почему бы просто не пройти длинный?
fn(data.begin(), data.end(), 0L);
Помимо этого вы, вероятно, могли бы сделать что-то вроде этого:
#include <type_traits>
template<typename Iterator>
typename std::iterator_traits<Iterator>::value_type fn(
Iterator first,
Iterator last,
typename std::iterator_traits<Iterator>::value_type init
);
Я действительно не понимаю, как вы рискуете переполнения, хотя.
Как:
0 is an int
0L is a long
Вам просто нужно вызвать метод с правильным аргументом:
как:
fn(data.begin(), data.end(), 0L);
как:
long init = 0; // result in 0L
fn(data.begin(), data.end(), init);
как:
fn(data.begin(), data.end(), static_cast<long>(0));
Один из способов написать fn
чтобы не называть это правильно
template<typename Iterator>
auto fn(Iterator first, Iterator last, typename std::decay<decltype(*first)>::type init)
-> typename std::decay<decltype(*first)>::type;