Ограничения на типы шаблонов

Предположим, я хочу реализовать общий более высокий порядок Map функция в C ++. Map должен взять контейнер и функцию преобразования и вернуть контейнер того же типа, но, возможно, с элементами другого типа.

Давайте принимать vector например:

template <typename InT, typename OutT, typename Tr>
vector<OutT> Map(vector<InT> cont, Tr tr)
{
OutCont out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++ot)
{
*oit = tr(*it);
}
}

который я хочу использовать так:

vector<int> v(10);
std::iota(v.begin(), v.end(), 0);
auto x = Map(v, [](int x) -> int {return x * 2;});

Это терпит неудачу в VC ++ 2012, давая мне следующую ошибку:

error C2783: 'std::vector<OutT> Map(std::vector<_Ty>,Tr)' : could not deduce template argument for 'OutT'

Мне кажется, что компилятор имеет всю необходимую информацию, потому что я явно определил тип возвращаемого значения в лямбда-выражении. Это можно обойти?

Приведенный выше пример использует vector, Есть ли способ использовать универсальный тип, чтобы типы ввода и вывода были одинаковыми? Например, если у меня есть входной контейнер, определенный как vector<string> и функция преобразования tr(string a) -> intтогда моя цель — заставить компилятор выяснить тип вывода vector<int>, Вот псевдокод того, чего я хочу достичь:

template <typename Cont<InT>, typename Cont<OutT>, typename Tr<InT, OutT>>
Cont<OutT> Map(Cont<InT> cont, Tr<InT, OutT> tr)
{
// Implementation
}

4

Решение

Вы можете написать что-то вроде:

template <typename InT, typename Tr>
auto Map(std::vector<InT> cont, Tr tr) -> std::vector<decltype(tr(cont[0]))>
{
std::vector<decltype(tr(cont[0]))> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}

Тип вывода выводится.

[Редактировать] Для более общей функции с большим контейнером:

template <template<typename, typename...> class Container, typename InT, typename Tr, typename... Args>
auto Map(const Container<InT, Args...>& cont, Tr tr) -> Container<decltype(tr(cont[0])), Args...>
{
Container<decltype(tr(cont[0])), Args...> out(cont.size());
auto oit = out.begin();
for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit)
{
*oit = tr(*it);
}
return out;
}

Обратите внимание на typename... нужно потому что std::vector также можно взять распределитель

4

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

Других решений пока нет …