使用多个输入向量中值的笛卡尔乘积调用 lambda
Call lambda with the cartesian product of values in multiple input vectors
我有几个int
s或double
s的向量:
std::vector<int> iv = { 1, 2, 3, 4 };
std::vector<double> jv = { .5, 1., 1.5, 2. };
std::vector<int> kv = { 5, 4, 3, 2 };
我需要处理每个向量的笛卡尔积:
for (int i : iv)
{
for (double j : jv)
{
for (int k : kv)
{
process(i, j, k);
}
}
}
我想将其扁平化为单个调用
product(iv, jv, kv, [=](int i, double j, int k)
{
process(i, j, k);
});
- 输入向量的数量是可变的
- 存储在输入向量中的类型是可变的
这可能吗?(我正在使用 C++14(
这是一个简短的递归版本,仅适用于任何可迭代对象。为了简单起见,它通过const&
来获取所有内容:
template <typename F>
void product(F f) {
f();
}
template <typename F, typename C1, typename... Cs>
void product(F f, C1 const& c1, Cs const&... cs) {
for (auto const& e1 : c1) {
product([&](auto const&... es){
f(e1, es...);
}, cs...);
}
}
这将是:
product(process, iv, jv, kv);
您使用 C++14 以便您可以使用std::index_sequence
/std::make_index_sequence
/std::index_sequence_for
...
我建议调用product()
先传递函数,然后再传递向量。
我的意思是
product([=](int i, double j, int k) { process(i, j, k); }, iv, jv, kv);
这样,您可以将可变参数模板用于矢量。
我还建议以下辅助函数
template <typename F, std::size_t ... Is, typename Tp>
void productH (F f, std::index_sequence<Is...> const &, Tp const & tp)
{ f(std::get<Is>(tp)...); }
template <typename F, typename Is, typename Tp, typename T0, typename ... Ts>
void productH (F f, Is const & is, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, is, std::tuple_cat(tp, std::tie(val)), ts...);
}
所以product()
简单地成为
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::index_sequence_for<Ts...>{}, std::make_tuple(), ts...); }
这个想法是在std::tuple
中提取和积累价值观。给定最终std::tuple
,调用函数,使用std::get
从std::tuple
中提取值,并使用std::index_sequence_for
生成的索引。
观察向量不需要是std::vector
s;可以是std::queue
、std::array
等。
以下是完整的编译示例
#include <array>
#include <tuple>
#include <deque>
#include <vector>
#include <utility>
#include <iostream>
template <typename F, std::size_t ... Is, typename Tp>
void productH (F f, std::index_sequence<Is...> const &, Tp const & tp)
{ f(std::get<Is>(tp)...); }
template <typename F, typename Is, typename Tp, typename T0, typename ... Ts>
void productH (F f, Is const & is, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, is, std::tuple_cat(tp, std::tie(val)), ts...);
}
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::index_sequence_for<Ts...>{}, std::make_tuple(), ts...); }
void process (int i1, double d1, int i2)
{ std::cout << '[' << i1 << ',' << d1 << ',' << i2 << ']' << std::endl; }
int main ()
{
std::vector<int> iv = { 1, 2, 3, 4 };
std::array<double, 4u> jv = { { .5, 1., 1.5, 2. } };
std::deque<int> kv = { 5, 4, 3, 2 };
product([=](int i, double j, int k) { process(i, j, k); }, iv, jv, kv);
}
不幸的是,您不能使用C++17,您可以避免std::index_sequence
/std::index_sequence_for
/std::get()
部分并按如下方式使用std::apply()
template <typename F, typename Tp>
void productH (F f, Tp const & tp)
{ std::apply(f, tp); }
template <typename F, typename Tp, typename T0, typename ... Ts>
void productH (F f, Tp const & tp, T0 const & t0, Ts ... ts)
{
for ( auto const & val : t0 )
productH(f, std::tuple_cat(tp, std::tie(val)), ts...);
}
template <typename F, typename ... Ts>
void product (F f, Ts ... ts)
{ productH(f, std::make_tuple(), ts...); }
这是我的解决方案。这可能不是最佳的,但它有效。
一个缺点是它仅适用于随机访问容器。
我将调用语法从product(a, b, c, lambda)
更改为product(a, b, c)(lambda)
,因为这个语法更容易实现。
#include <cstddef>
#include <iostream>
#include <vector>
#include <utility>
template <typename ...P, std::size_t ...I>
auto product_impl(std::index_sequence<I...>, const P &...lists)
{
return [&lists...](auto &&func)
{
std::size_t sizes[]{lists.size()...};
std::size_t indices[sizeof...(P)]{};
std::size_t i = 0;
while (i != sizeof...(P))
{
func(lists[indices[I]]...);
for (i = 0; i < sizeof...(P); i++)
{
indices[i]++;
if (indices[i] == sizes[i])
indices[i] = 0;
else
break;
}
}
};
}
template <typename ...P>
auto product(const P &...lists)
{
return product_impl(std::make_index_sequence<sizeof...(P)>{}, lists...);
}
int main()
{
std::vector<int> a = {1,2,3};
std::vector<float> b = {0.1, 0.2};
std::vector<int> c = {10, 20};
product(a, b, c)([](int x, float y, int z)
{
std::cout << x << " " << y << " " << z << 'n';
});
/* Output:
1 0.1 10
2 0.1 10
3 0.1 10
1 0.2 10
2 0.2 10
3 0.2 10
1 0.1 20
2 0.1 20
3 0.1 20
1 0.2 20
2 0.2 20
3 0.2 20
*/
}
现场试用
这是通过解释Barry的代码:
#include <iostream>
template <typename F>
void product(F f) {
f();
}
template <typename F, typename C1, typename... Cs>
void product(F f, C1 const& c1, Cs const&... cs) {
product([&] ( auto const&... es){
f(c1,es...);
},
cs...);
}
void process(int i, double j, int k)
{
std::cout << i << " " << j << " " << k << std::endl;
}
int main()
{
product(process, 1, 1.0, 2);
}
这只是一种调用process.
的奇特方式 关键是f(c1,es...)
创建了一个f
的柯里函数,其中第一个参数被锁定到c1
。因此,当cs
变为空时,所有参数都被柯里化,f()
调用process(1,1.0,2)
请注意,此柯里仅在编译时可用,而不是运行时可用。
- 在 OpenGL 中将笛卡尔世界坐标转换为球面局部坐标
- C++ 中unordered_map的有效笛卡尔积
- 谷歌测试:模板模板的笛卡尔乘积的类型列表与模板
- 使用多个输入向量中值的笛卡尔乘积调用 lambda
- 如何在C++中创建类型列表的 n 路笛卡尔积?
- c++17通过生成预先声明的类型列表的笛卡尔乘积来生成std::变体
- 用于将笛卡尔 (x,y,z) 转换为圆柱坐标 (ρ,θ,z) 坐标 2D/3D 的代码
- 将笛卡尔点存储在矢量和输出距离中
- 使用迭代器和可变参数模板的笛卡尔乘积
- 圆的面积 使用笛卡尔平面上的点
- 当元素数> 1000 时,如何制作向量的笛卡尔积?
- 使用提示用户输入笛卡尔平面中某些点的x-y坐标(浮点类型)的函数
- 创建两个可变非类型模板参数包的笛卡尔乘积扩展
- 如何根据过滤的数据创建笛卡尔产品范围
- 使用笛卡尔产品查找唯一BST数量的直觉
- 有没有STL函数可以得到两个C++向量的笛卡尔乘积
- TMP:如何推广向量的笛卡尔积
- c++中的笛卡尔乘积
- 用坐标搜索笛卡尔平面上的几何图形
- 就地生成 2 个向量的笛卡尔积<string>?