是否可以使用迭代器创建成员字段的值列表?
Is it possible to create a list of values of member fields using iterators?
考虑以下结构
struct Pair
{
int a;
std::string b;
};
我有一个 std::vector<Pair> pairs
,但我想要一个 std::vector<std::string> listOfBFromPairs
,其中包含对列表中 b 的所有值。
我想单行完成。
我以前用过OpenGL,我之前创建了一个结构体,指定了一个起点
pairs.begin() + offsetof(Pair, b)
并给定一个步长(内存中 pair 对象的大小)和我想要解析的东西的数量,它已经完成了我在这里的任务。
这里也可以使用 C++ 迭代器吗?
我的具体用例是我想创建一个 无序集 Vulkan 扩展名称,但 Vulkan returns 结构包含扩展名称作为成员。然后我将使用无序集来检查我的应用程序想要使用的扩展。
I want a std::vector<std::string> listOfBFromPairs
which contains
all the values of b
from the list of pairs
.
I would like to do this in a one-liner?
当然可以。你可以像这样使用 std::transform
from <algorithm>
header
#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<std::string> 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; }
);
正如您所要求的 one-liner,这是一种提升方法(恕我直言,可读性不高):
#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)));
如果目标容器是例如a 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 范围实现类似的效果。
考虑以下结构
struct Pair
{
int a;
std::string b;
};
我有一个 std::vector<Pair> pairs
,但我想要一个 std::vector<std::string> listOfBFromPairs
,其中包含对列表中 b 的所有值。
我想单行完成。
我以前用过OpenGL,我之前创建了一个结构体,指定了一个起点
pairs.begin() + offsetof(Pair, b)
并给定一个步长(内存中 pair 对象的大小)和我想要解析的东西的数量,它已经完成了我在这里的任务。
这里也可以使用 C++ 迭代器吗?
我的具体用例是我想创建一个 无序集 Vulkan 扩展名称,但 Vulkan returns 结构包含扩展名称作为成员。然后我将使用无序集来检查我的应用程序想要使用的扩展。
I want a
std::vector<std::string> listOfBFromPairs
which contains all the values ofb
from the list ofpairs
.I would like to do this in a one-liner?
当然可以。你可以像这样使用 std::transform
from <algorithm>
header
#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<std::string> listOfBFromPairs;
而不是字符串向量。在这种情况下,您需要使用 std::inserter
.
#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; }
);
正如您所要求的 one-liner,这是一种提升方法(恕我直言,可读性不高):
#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)));
如果目标容器是例如a 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 范围实现类似的效果。