const std::vector<int>給定一個std::vector<std::tuple<int, float>>建構式引數,我想在建構式的初始化串列中初始化一個成員變數。該向量應包含所有第一個元組項。
是否有一個單行從 中提取std::vector<int>包含所有第一個元組條目的std::vector<std::tuple<int, float>>?
uj5u.com熱心網友回復:
使用 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>}
{}
};
使用范圍-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>()}
{}
};
還有一個科學怪人的怪物:
#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>()}
{}
};
uj5u.com熱心網友回復:
不是單行設定,但肯定可以使用 - 您可以撰寫一個函式來進行轉換,然后建構式可以在初始化向量成員時呼叫該函式,例如:
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))
{
}
};
uj5u.com熱心網友回復:
添加到@bolov 的答案中,讓我們談談您可能喜歡做什么,但不能單行。
to<>()@bolov 的答案中有一個來自 range-v3的函式——它將一個范圍具體化到一個實際的容器中(一個范圍是惰性求值的,當你創建它時,你實際上并沒有迭代元素)。如果你問我,它沒有理由不應該出現在標準庫中——也許他們會在 2023 年添加它?您可能想知道 - 為什么我需要它
to()?我不能只按范圍初始化一個向量嗎?答案是 - 有點,有時,也許。考慮這個程式:#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<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() }; }該
vec1陳述句將編譯得很好,但該vec2陳述句將失敗(GodBolt.org)。這令人驚訝(無論如何對我來說)!您可能還想知道為什么您甚至需要遍歷范圍。為什么沒有...
template <typename Container, typename UnaryOperation> auto transform(const Container& container, UnaryOperation op);哪個構造轉換后的容器作為其回傳值?這將允許你寫:
std::vector<int> vec3 { transform( tvec, [](const pair_type& p) { return std::get<0>(p); } ) }......鮑勃是你的叔叔。好吧,我們只是在 C 標準庫中沒有接受容器的函式。它要么是迭代器對,它是“經典的”C 20 之前的標準庫,要么是范圍。
現在,按照我宣告
transform()函式的方式,實際上很難/不可能實作,因為您沒有辦法將容器的型別轉換為相同型別的容器但具有不同的元素。所以,相反,讓我們寫一些更簡單的東西:template < typename T, template <typename> class Container, typename UnaryOperation > auto transform(const Container<T>& container, UnaryOperation op) { auto tv = std::ranges::transform_view(container, op); using op_result = decltype(op(*container.begin())); return Container<op_result> { tv.begin(), tv.end() }; }這有效(GodBolt.org)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/346460.html
