[英]c++ get std::vector<int> from std::vector<std::tuple<int, float>>
i want to initialize a const std::vector<int>
member variable in the initializer list of a constructor, given a std::vector<std::tuple<int, float>>
constructor argument.我想在构造函数的初始化列表中初始化一个
const std::vector<int>
成员变量,给定一个std::vector<std::tuple<int, float>>
构造函数参数。 The vector should contain all the first tuple items.该向量应包含所有第一个元组项。
Is there a one-liner that extracts an std::vector<int>
containing all the first tuple entries from an std::vector<std::tuple<int, float>>
?是否有一衬垫,其提取一个
std::vector<int>
包含所有第一元组从条目std::vector<std::tuple<int, float>>
?
With C++20 ranges:使用 C++20 范围:
struct X
{
const std::vector<int> v;
template <std::ranges::range R>
requires std::convertible_to<std::ranges::range_value_t<R>, int>
X(R r)
: v{r.begin(), r.end()}
{}
X(const std::vector<std::tuple<int, float>>& vt)
: X{vt | std::ranges::views::elements<0>}
{}
};
With ranges-v3:使用范围-v3:
struct X
{
const std::vector<int> v;
X(const std::vector<std::tuple<int, float>>& vt)
: v{vt | ranges::views::transform([] (auto t) {
return std::get<0>(t); })
| ranges::to<std::vector>()}
{}
};
And a Frankenstein's monster:还有一个科学怪人的怪物:
#include <ranges>
#include <range/v3/range/conversion.hpp>
struct X
{
const std::vector<int> v;
X(const std::vector<std::tuple<int, float>>& vt)
: v{vt | std::ranges::views::elements<0>
| ranges::to<std::vector>()}
{}
};
Adding to @bolov's answer, let's talk about what you might have liked to do, but can't in a one-liner.添加到@bolov 的答案中,让我们谈谈您可能喜欢做什么,但不能单行。
There's the to<>()
function from ranges-v3 from @bolov 's answer - it materializes a range into an actual container (a range is lazily-evaluated, and when you create it you don't actually iterate over the elements). @bolov 的答案中有来自 range-v3 的
to<>()
函数 - 它将一个范围具体化到一个实际的容器中(一个范围是惰性求值的,当你创建它时,你实际上并没有迭代元素) . There is no reason it shouldn't be in the standard library, if you ask me - maybe they'll add it 2023?如果你问我,它没有理由不应该出现在标准库中——也许他们会在 2023 年添加它?
You may be wondering - why do I need that to()
?你可能想知道 - 为什么我需要那个
to()
? Can't I just initialize a vector by a range?我不能按范围初始化一个向量吗? And the answer is - sort of, sometimes, maybe.
答案是 - 有点,有时,也许。 Consider this program:
考虑这个程序:
#include <vector> #include <tuple> #include <ranges> void foo() { using pair_type = std::tuple<int, double>; std::vector<pair_type> tvec { {12, 3.4}, {56, 7.8}, { 90, 91.2} }; auto tv = std::ranges::transform_view( tvec, [](const pair_type& p) { return std::get<0>(p);} ); std::vector<std::tuple<int>> vec1 { tv.begin(), tv.end() }; std::vector<std::tuple<int>> vec2 { std::ranges::transform_view{ tvec, [](const pair_type& p) { return std::get<0>(p);} }.begin(), std::ranges::transform_view{ tvec, [](const pair_type& p) { return std::get<0>(p);} }.end() }; }
The vec1
statement will compile just fine, but the vec2
statement will fail . vec1
语句将编译得很好,但vec2
语句将失败。 This is surprising (to me anyway)!这令人惊讶(无论如何对我来说)!
You may also be wondering why you even need to go through ranges at all.您可能还想知道为什么您甚至需要遍历范围。 Why isn't there a...
为什么没有...
template <typename Container, typename UnaryOperation> auto transform(Container&& container, UnaryOperation op);
which constructs the transformed container as its return value?哪个构造转换后的容器作为其返回值? That would allow you to write:
这将允许你写:
std::vector<std::tuple<int>> vec3 { transform( tvec, [](const pair_type& p) { return std::get<0>(p); } ) }
... and have that work. ......并完成这项工作。 Well, we just don't have functions in the standard libraries which take containers.
好吧,我们只是在标准库中没有使用容器的函数。 It's either iterator pairs, which is the "classic" pre-C++20 standard library, or ranges.
它要么是迭代器对,它是“经典的”C++20 之前的标准库,要么是范围。 But there is nothing preventing you from writing that very function!
但是没有什么可以阻止您编写该函数! It's not even that difficult, except perhaps with the care you need for the forwarding reference.
这甚至不是那么困难,除非您需要注意转发参考。
Not a one-liner to setup, but certainly one to use - you can write a function to do the conversion, and then the constructor can call that function when initializing the vector member, eg:不是单行设置,但肯定可以使用 - 您可以编写一个函数来进行转换,然后构造函数可以在初始化向量成员时调用该函数,例如:
std::vector<int> convertVec(const std::vector<std::tuple<int, float>> &arg)
{
std::vector<int> vec;
vec.reserve(arg.size());
std::transform(arg.begin(), arg.end(), std::back_inserter(vec),
[](const std::tuple<int, float> &t){ return std::get<int>(t); }
);
return vec;
}
struct Test
{
const std::vector<int> vec;
Test(const std::vector<std::tuple<int, float>> &arg)
: vec(convertVec(arg))
{
}
};
Yes, there is a one-liner if you use this library in Github .是的,如果您在 Github 中使用此库,则有一个单行。
The code goes like this.代码是这样的。
#include <iostream>
#include <tuple>
#include <vector>
#include <LazyExpression/LazyExpression.h>
using std::vector;
using std::tuple;
using std::ref;
using std::cout;
using LazyExpression::Expression;
int main()
{
// Define test data
vector<tuple<int, float>> vecTuple { {1,1.1}, {2,2.2}, {3, 3.3} };
// Initialize int vector with the int part of the tuple (the one-liner :)
vector<int> vecInt = Expression([](const tuple<int, float>& t) { return std::get<int>(t); }, ref(vecTuple))();
// print the results
for (int i : vecInt)
cout << i << ' ';
cout << "\n";
}
// Output: 1 2 3
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.