迭代参数包中的向量

Iterating over vectors in a parameter pack

我有一个接受向量参数包的函数,这些向量的长度相同,我想在每个索引处调用一个函数,其中包含这两个向量的值。

例如,我传入一个函数,该函数打印出我传入的两个整数。我将两个整数向量放入该函数,它会为每个索引调用我传入的函数,代码可能有助于解释我想做什么

#include <iostream>
#include <thread>
#include <functional>
#include <vector>

template<
    typename RETURN,
    typename ... INPUTS
>
std::vector<RETURN> thread_transform(std::function<RETURN(INPUTS ...)> function, std::vector<INPUTS>& ... inputs)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    /* Code to loop over the vectors in 'inputs' and call 'function' with */
}

int func(int a, int b)
{
    std::cout << a << ' ' << b << std::endl;
}

int main(int argc, char** argv)
{
    std::vector<int> a;
    std::vector<int> b;
    std::vector<int> ret = thread_transform(std::function<int(int, int)>(func), a, b);
    return 0;
}

大概是这样的:

template<typename RETURN, typename ... INPUTS>
std::vector<RETURN> thread_transform(
    std::function<RETURN(INPUTS ...)> function,
    std::vector<INPUTS>& ... inputs)
{
    std::vector<RETURN> ret;
    auto size = std::min({inputs.size()...});
    for (int i = 0; i < size; ++i) {
        ret.push_back(function(inputs[i]...));
    }
    return ret;
}

非常简单。 Demo

我建议简化函数的签名,而不是对 vectorsstd::function 进行硬编码。

既然你已经定义了一个函数模板,你不妨接受任何范围和任何可调用的:

Live On Compiler Explorer

template <typename F, typename... Rs>
auto zip(F f, Rs const&... args) {
    using R = std::decay_t<
        std::invoke_result_t<F, typename Rs::value_type...>
    >;
    auto const n = std::min({args.size()...});
    std::vector<R> r(n);
    for (size_t i = 0; i<n; ++i)
        r[i] = f(args[i]...);
    return r;
}

事实上,当你概括时,你最终会得到 RangeV3 的 zip_with:

template <typename F, typename... Rs>
auto my_zip(F&& f, Rs const&... args) {
    return r::to_vector(v::zip_with(f, args...));
}

我认为您可以在默认情况下不使用 to_vector

Live On Compiler Explorer

#include <fmt/ranges.h>
#include <functional>
#include <iostream>
#include <map>
#include <range/v3/all.hpp>
#include <vector>

namespace r = ::ranges;
namespace v = r::views;
using namespace std::string_literals;

template <typename F, typename... Rs>
auto zip(F f, Rs const&... args) {
    return v::zip_with(std::move(f), args...);
}

template <typename F, typename... Rs>
auto zip_vec(F const& f, Rs const&... args) {
    return r::to_vector(zip(f, args...));
}

auto foo(int x, std::string_view s) {
    std::string r(s.size() * x, '[=12=]');
    while (x--) {
        std::copy(s.begin(), s.end(), r.begin() + x * s.size());
    }
    return r;
}

int main() {
    std::vector<int> a{ 1, 3 }, b{ 2, -2 };

    auto mul = std::multiplies<>{};
    fmt::print("{} x {} -> {}\n", a, b, zip(mul, a, b));

    auto ret = zip_vec(std::plus<>{}, a, b);
    fmt::print("ret as a vector: {}\n", ret);
    static_assert(std::is_same_v<decltype(ret), std::vector<int>>);

    std::map<std::string, int> m { {"one"s, 1}, {"three"s, 3} };
    fmt::print("But also using a non-vectors: {}\nor {}\n",
    zip(foo, a, m | v::keys),
    zip(mul, a, m | v::values));
}

版画

{1, 3} x {2, -2} -> {2, -6}
ret as a vector: {3, 1}
But also using a non-vectors: {"one", "threethreethree"}
or {1, 9}