Устранение неоднозначного вызова в выводе аргумента шаблона

Типичная подпись шаблона функции:

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 ниже. Спасибо за помощь.

0

Решение

Почему бы просто не пройти длинный?

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

Живая демо

Я действительно не понимаю, как вы рискуете переполнения, хотя.

2

Другие решения

Как:

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