迭代参数包中的向量
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
我建议简化函数的签名,而不是对 vectors
或 std::function
进行硬编码。
既然你已经定义了一个函数模板,你不妨接受任何范围和任何可调用的:
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
。
#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}
我有一个接受向量参数包的函数,这些向量的长度相同,我想在每个索引处调用一个函数,其中包含这两个向量的值。
例如,我传入一个函数,该函数打印出我传入的两个整数。我将两个整数向量放入该函数,它会为每个索引调用我传入的函数,代码可能有助于解释我想做什么
#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
我建议简化函数的签名,而不是对 vectors
或 std::function
进行硬编码。
既然你已经定义了一个函数模板,你不妨接受任何范围和任何可调用的:
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
。
#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}