c++ - 给定一个具有任意数量的具有不同类型的向量的元组,我如何提取具有最小大小的向量?
问题描述
在我的应用程序中,我生成了一个包含许多包含值的向量的元组。我想有一种通用的方法来遍历元组以提取具有最小值的单个向量。
例如:
auto t = std::make_tuple(std::vector<int>({1,2}), std::vector<double>({1.0, 2.0, 3.0}));
如何提取包含最小值的向量?
解决方案
给定一个包含不同类型向量的元组,我如何提取最小大小的向量?
你不能你不能直接。
因为它们是不同的类型,所以决定是基于值(而不是类型),所以你无法决定提取的编译时间(std::tuple
can't be constexpr
)的类型,而C++是一种强类型语言。
您可以做的最简单的事情是提取具有最小大小的向量的索引。因为在这种情况下,提取的值是一个整数(std::size_t
例如),您可以遍历元组中的向量以选择具有较少元素的向量。
不同的是,如果您必须提取std::array
最小尺寸的
auto t = std::make_tuple(std::array<int, 2u>({1,2}),
std::array<double, 3u>({1.0, 2.0, 3.0}));
因为大小(2u
第一个,3u
第二个)是已知的编译时间,所以你可以选择第二个数组编译时间。
如果您可以使用 C++17,则可以使用std::variant
, 一个可以包含所有类型的元组的类型。
正如 Caleth 所指出的(谢谢),如果您只能将 C++11/C++14 与 boost 库一起使用,则可以使用boost::variant
. 但我不知道,所以我不能给你看一个具体的例子(但你可以看到 Caleth 的回答)
以下是具有两种类型的元组的示例
template <typename T1, typename T2>
std::variant<T1, T2> getLess (std::tuple<T1, T2> const & tp)
{
std::variant<T1, T2> v;
if ( std::get<0>(tp).size() < std::get<1>(tp).size() )
v = std::get<0>(tp);
else
v = std::get<1>(tp);
return v;
}
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
auto gl = getLess(std::make_tuple(vi, vd));
}
这适用于两种类型的元组。但是使用 N 类型的元组(N
高)变得复杂,因为你不能写一些东西
auto min_length = std::get<0>(tp).size();
auto min_index = 0u;
for ( auto ui = 1u ; ui < N ; ++ui )
if ( std::get<ui>(tp).size() < min_length )
{
min_length = std::get<ui>(tp).size();
min_index = ui;
}
因为您不能将std::get<>()
运行时值作为ui
.
分配变体的同样问题。你不能简单地写
v = std::get<min_index>(tp);
因为min_index
是运行时值。
你必须通过一个switch()
switch ( min_length )
{
case 0: v = std::get<0>(tp); break;
case 1: v = std::get<1>(tp); break;
case 2: v = std::get<2>(tp); break;
case 3: v = std::get<3>(tp); break;
case 4: v = std::get<4>(tp); break;
// ...
case N-1: v = std::get<N-1>(tp); break;
};
或类似的东西。
getLess()
如您所见,如果您希望该函数是可变参数,它会变得越来越复杂。
对于可变参数情况,我能想象的最好的(但是是 C++17 解决方案;请参阅 Caleth 对 C++11 解决方案的回答)是使用辅助函数和模板折叠,如下所示。
#include <tuple>
#include <vector>
#include <variant>
#include <iostream>
template <typename ... Ts, std::size_t ... Is>
auto getLessHelper (std::tuple<Ts...> const & tp,
std::index_sequence<0, Is...> const &)
{
std::variant<Ts...> var_ret { std::get<0>(tp) };
std::size_t min_size { std::get<0>(tp).size() };
((std::get<Is>(tp).size() < min_size ? (var_ret = std::get<Is>(tp),
min_size = std::get<Is>(tp).size())
: 0u), ...);
return var_ret;
}
template <typename ... Ts>
auto getLess (std::tuple<Ts...> const & tp)
{ return getLessHelper(tp, std::index_sequence_for<Ts...>{}); }
int main ()
{
std::vector<int> vi {1, 2, 3};
std::vector<double> vd {1.0, 2.0};
std::vector<float> vf {1.0f};
auto gl = getLess(std::make_tuple(vi, vd, vf));
std::cout << std::visit([](auto const & v){ return v.size(); }, gl)
<< std::endl; // print 1, the size() of vf
}
推荐阅读
- python - Python Pandas - 合并不同大小的数据帧并用匹配的列替换行中的值
- google-apps-script - 如何将公式生成的二维码作为图像放置在谷歌文档中(导出为 PDF)?
- python - Flask 会话:文件系统的 OSError:[Errno 36] 文件名太长
- protractor - 从 Protractor 迁移到 Cypress 自动化测试框架
- python - pysnmp - 在 Cisco 交换机上使用 snmpv3 拉取每个 vlan 的 MAC 地址表
- python - Python - Matplotlib y 轴混淆(缩放)
- networking - 如何将多播消息转发到第二个网络上的设备
- macos - 在没有 T2 芯片的 Mac 上的 FileVault 加密启动卷上,在 macOS Catalina 和 Big Sur 上安装 Nix 时出错
- python - 如何转到 .txt 文件中的下一行?
- javascript - Heroku 应用程序上的外部数据库连接传递身份验证错误