Как обобщить функции, которые действуют на вектор разных типов? - PullRequest
0 голосов
/ 01 сентября 2018

Я относительно новичок в C ++ и не могу правильно сформулировать свой вопрос. Так как векторизация и карта имеют оба значения, которые кажутся отличными от того, что я ищу (поэтому поиск в Google решения затруднен).

У меня много функций, действующих на отдельные объекты произвольного типа. Я хочу, чтобы общий способ (то есть шаблон или функция-обертка) преобразовывал их в функции, действующие на векторы произвольного числа объектов одного типа.

Пример:

int func1(int a) {return a+1;}
long func2(long a) {return a*10;}

vector<int> func1(vector<int> a_vec)
{
    vector<int> out_vec;
    for (int i = 0; i < a_vec.size(); i++)
        out_vec.push_back(func1(a_vec[i]));
    return out_vec;
}

vector<long> func2(vector<long> a_vec)
{
    vector<long> out_vec;
    for (int i = 0; i < a_vec.size(); i++)
        out_vec.push_back(func2(a_vec[i]));
    return out_vec;
}

Шаблоны кажутся необходимыми, но у меня пока нет большого опыта работы с ними, и я не знаю, как их применять в этом случае. Любые ссылки / предложения / комментарии приветствуются.

(Также, пожалуйста, добавьте соответствующие теги - поскольку я не уверен в правильности этого термина, я не уверен, как его пометить).

Ответы [ 3 ]

0 голосов
/ 01 сентября 2018

Да, вам понадобятся шаблоны, так как вы не знаете, с какими типами вы будете использовать эту функцию векторизации.

Давайте попробуем это:

#include <vector>
#include <iostream>

int func1(int i){ return i + 1; }

template<typename valueT, typename callableT>
std::vector<valueT> vectorize(const std::vector<valueT>& input, callableT funcToCall)
{
    std::vector<valueT> result;
    for (auto& x : input) result.push_back(funcToCall(x));
    return result;
}


int main()
{
    std::vector<int> iVector{2,3,5,7,11,13,17};

    std::vector<int> output = vectorize(iVector, &func1);

    for (const auto& x : output) std::cout << x << std::endl;

    return 0;
}
0 голосов
/ 02 сентября 2018

Как упомянуто в комментарии @ paler123, вы можете использовать std::transform для выполнения работы + небольшую шаблонную функцию.

Поскольку ваши две функции имеют сходство в сигнатуре функции

i.e, Type function(Type arg)

Я выбрал типизированные указатели функций в качестве параметров функции шаблона.

template<typename Type>
std::vector<Type> func(const std::vector<Type>& a_vec, Type(*func)(Type))
{
    std::vector<Type> out_vec; out_vec.reserve(a_vec.size());
    std::transform(a_vec.begin(), a_vec.end(), std::back_inserter(out_vec), func);
    return out_vec;
}

Теперь в main() вы можете либо явно указать тип, либо оставить его как есть и позволить компилятору делать вывод типа.

auto result = func<int>({ 1,2,3,4 }, func1);
// also can
auto result2 = func({ 1, 2, 3, 4 }, func2);

См. пример выходных данных здесь

0 голосов
/ 01 сентября 2018

Этот код действительно подходит для некоторых шаблонов.

template <typename T, typename TFunc>
std::vector<T> transform(const std::vector<T> &v, TFunc &&func)
{
    std::vector<T> result;
    result.reserve(v.size());
    for (auto &&element : v)
        result.push_back(std::invoke(func, element));
    return result;
}

Как вы могли заметить, функция выглядит очень похоже на std::transform, которая работает на итераторах вместо векторов. Это можно назвать как:

 auto result = transform(v, &func1);
...