[英]How to get the type of the values in a C++20 std::ranges range?
Given a std::ranges::range
in C++20, how can I determine the type of the values in that range?给定 C++20 中的
std::ranges::range
,如何确定该范围内值的类型?
I want to write a function that makes a std::vector
out of an arbitrary range.我想写一个 function 使
std::vector
超出任意范围。 I'd like this function to have a nice, explicit declaration.我希望这个 function 有一个很好的、明确的声明。 Something like:
就像是:
template<std::ranges::range Range>
std::vector<std::value_type_t<Range>> make_vector(Range const&);
The following seems to work, but the declaration is not explicit and the implementation is ugly (even ignoring that it doesn't allocate the right size up-front where possible).以下似乎有效,但声明不明确且实现很丑陋(甚至忽略它没有尽可能预先分配正确的大小)。
template<std::ranges::range Range>
auto make_vector(Range const& range)
{
using IteratorType = decltype(std::ranges::begin(std::declval<Range&>()));
using DerefType = decltype(*std::declval<IteratorType>());
using T = std::remove_cvref_t<DerefType>;
std::vector<T> retval;
for (auto const& x: range) {
retval.push_back(x);
}
return retval;
}
Is there a canonical/better/shorter/nicer way to do this?有没有规范/更好/更短/更好的方法来做到这一点?
The type trait you are looking for is spelled std::ranges::range_value_t
, not std::value_type_t
.您正在寻找的类型特征拼写为
std::ranges::range_value_t
,而不是std::value_type_t
。
Also, the whole function you are trying to write here is just a more limited version of std::ranges::to
coming in C++23.此外,您在这里尝试编写的整个 function 只是 C++23 中
std::ranges::to
的一个更有限的版本。
Let's go through this in order:让我们 go 依次通过这个:
template<std::ranges::range Range>
auto make_vector(Range const& range)
This is checking if Range
is a range, but range
isn't a Range
, it's a const Range
.这是检查
Range
是否是一个范围,但range
不是Range
,它是一个const Range
。 It's possible that R
is a range
but R const
is not, so you're not actually constraining this function properly. R
可能是一个range
,但R const
不是,所以您实际上并没有正确地限制这个 function。
The correct constraint would be:正确的约束是:
template<typename Range>
requires std::ranges::range<Range const>
auto make_vector(Range const& range)
But then that limits you to only const-iterable ranges (which is an unnecessary restriction) and then requires you to very carefully use Range const
throughout the body (which is very easy to forget).但这会限制您只能使用 const-iterable 范围(这是不必要的限制),然后需要您非常小心地在整个主体中使用
Range const
(这很容易忘记)。
Both of which are why, with ranges, you'll want to use forwarding references:这两者都是为什么,对于范围,你会想要使用转发引用:
template<std::ranges::range Range>
auto make_vector(Range&& range)
That'll constrain your function properly.这将正确限制您的 function 。
Next:下一个:
using IteratorType = decltype(std::ranges::begin(std::declval<Range&>()));
using DerefType = decltype(*std::declval<IteratorType>());
using T = std::remove_cvref_t<DerefType>;
There are type traits for these things directly:这些东西直接有类型特征:
using IteratorType = std::ranges::iterator_t<Range>;
using DerefType = std::iter_reference_t<IteratorType>;
Or:或者:
using DerefType = std::ranges::range_reference_t<Range>;
But also since you want the value type, that's (as already pointed out):但也因为你想要值类型,那就是(正如已经指出的那样):
using T = std::ranges::range_value_t<Range>;
Note that the value type is not necessarily just the reference type with the qualifiers removed.请注意,值类型不一定只是删除了限定符的引用类型。
Lastly:最后:
std::vector<T> retval;
for (auto const& x: range) {
retval.push_back(x);
}
return retval;
It'll be more efficient or even more correct to forward the element into push_back
(ie auto&& x
and then FWD(x)
, instead of auto const& x
and x
).将元素转发到
push_back
会更有效甚至更正确(即auto&& x
然后是FWD(x)
,而不是auto const& x
和x
)。
Additionally you'll want to, at the very least:此外,您至少需要:
if constexpr (std::ranges::sized_range<Range>) {
retval.reserve(std::ranges::size(range));
}
Since if we have the size readily available, it'll be nice to reduce the allocations to just the one.因为如果我们有随时可用的大小,那么将分配减少到只有一个会很好。
Lastly, in C++23, make_vector(r)
can just be spelled std::ranges::to<std::vector>(r)
.最后,在 C++23 中,
make_vector(r)
可以拼写为std::ranges::to<std::vector>(r)
。 This does the allocation optimization I mentioned, but can additionally be more performant since vector
's construction internally can avoid the constant checking to see if additional allocation is necessary (which is what push_back
has to do).这实现了我提到的分配优化,但还可以提高性能,因为
vector
的内部构造可以避免不断检查是否需要额外分配(这是push_back
必须做的)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.