是否可以使用迭代器创建成员字段的值列表?

Posted

技术标签:

【中文标题】是否可以使用迭代器创建成员字段的值列表?【英文标题】:Is it possible to create a list of values of member fields using iterators? 【发布时间】:2020-08-15 11:02:31 【问题描述】:

考虑以下结构

struct Pair 

   int a;
   std::string b;
;

我有一个 std::vector<Pair> pairs,但我想要一个 std::vector<std::string> listOfBFromPairs,它包含对列表中 b 的所有值。

我想在单行中做到这一点。

我之前用过OpenGL,之前创建了一个struct,指定了一个起点

pairs.begin() + offsetof(Pair, b)

并给定步长(内存中pair对象的大小)和我想要解析的东西的数量,它已经完成了我在这里所追求的。

这里也可以使用 c++ 迭代器吗?

我的具体用例是我想创建一个 无序集 Vulkan 扩展名,但 Vulkan 返回包含扩展名作为成员的结构。然后,我将使用无序集来检查我的应用程序想要使用的扩展。

【问题讨论】:

你关心重复吗?如果你不这样做,那么这是微不足道的。如果你这样做了,那么你要么需要选择 set 而不是 vector,要么之后需要删除重复项,但它不再是一个衬垫。 如果你想要一个 unordered_set 那么你为什么要创建一个向量呢?直接创建 unordered_set 即可。那将是一个班轮。 vulkan API 返回一个结构数组。 glfw API 返回一个字符串数组。它们保证是独一无二的。我正在使用无序集,因为我想要 O(1) 查找 【参考方案1】:

我想要一个std::vector<std::string> listOfBFromPairs,其中包含 pairs列表中b的所有值。

我想在单行中执行此操作?

当然可以。您可以像这样使用来自<algorithm> 标头的std::transform

#include <algorithm> // std::transform
#include <iterator>  // std::back_inserter

std::vector<Pair> pairs;
std::vector<std::string> listOfBFromPairs;
listOfBFromPairs.reserve(pairs.size()); // reserve the memory for unwanted reallocations

std::transform(pairs.begin(), pairs.end(),
   std::back_inserter(listOfBFromPairs), [](const Pair& pair)  return pair.b; 
);

但是,如果您需要使用 unordered_set 且没有重复项的 listOfBFromPairs,则需要创建一个 std::unordered_set&lt;std::string&gt; listOfBFromPairs; 而不是字符串向量。在这种情况下,您需要使用 std::inserter 将字符串插入 unordered_set。

#include <unordered_set>
#include <algorithm> // std::transform
#include <iterator>  // std::inserter

std::vector<Pair> pairs;
std::unordered_set<std::string> listOfBFromPairs;

std::transform(pairs.begin(), pairs.end(),
   std::inserter(listOfBFromPairs, listOfBFromPairs.end()), [](const auto& pair)  return pair.b; 
);

【讨论】:

【参考方案2】:

正如您要求的单线,这是一种 Boost 方法(恕我直言,不太可读):

#include <boost/range/adaptor/transformed.hpp>
#include <functional>

const std::vector<Pair> src;

const auto listOfBFromPairs = boost::copy_range<std::vector<std::string>>(src | boost::adaptors::transformed(std::mem_fn(&Pair::b)));

如果目标容器是例如一个std::unordered_set,把最后一行改成

const auto listOfBFromPairs = boost::copy_range<std::unordered_set<std::string>>(src | boost::adaptors::transformed(std::mem_fn(&Pair::b)));

(只有copy_range 的实例化发生了变化)。您可以使用 C++20 范围实现类似的效果。

【讨论】:

以上是关于是否可以使用迭代器创建成员字段的值列表?的主要内容,如果未能解决你的问题,请参考以下文章

迭代器的注意事项

为啥迭代器指向的数据在从列表中删除后保留

如何为一长串整数创建优化的迭代器?

python-迭代器与生成器1

迭代器

Python生成器&迭代器