我有多个int
或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)
答案 0 :(得分:6)
这是一个简短的递归版本,仅适用于所有可迭代对象。为了简单起见,它使用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);
答案 1 :(得分:3)
您使用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::tuple
从std::get
提取值,并使用std::index_sequence_for
生成索引。
注意到没有必要向量是std::vector
;可以是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...); }
答案 2 :(得分:2)
这是我的解决方案。这可能不是最佳选择,但是可以。
一个缺点是它仅适用于随机访问容器。
我将调用语法从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
*/
}
答案 3 :(得分:0)
这是通过解释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)
,请注意,此计算仅在编译时可用,而在运行时不可用。