[英]How to get the type of the values in a C++20 std::ranges range?
给定 C++20 中的std::ranges::range
,如何确定该范围内值的类型?
我想写一个 function 使std::vector
超出任意范围。 我希望这个 function 有一个很好的、明确的声明。 就像是:
template<std::ranges::range Range>
std::vector<std::value_type_t<Range>> make_vector(Range const&);
以下似乎有效,但声明不明确且实现很丑陋(甚至忽略它没有尽可能预先分配正确的大小)。
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;
}
有没有规范/更好/更短/更好的方法来做到这一点?
您正在寻找的类型特征拼写为std::ranges::range_value_t
,而不是std::value_type_t
。
此外,您在这里尝试编写的整个 function 只是 C++23 中std::ranges::to
的一个更有限的版本。
让我们 go 依次通过这个:
template<std::ranges::range Range>
auto make_vector(Range const& range)
这是检查Range
是否是一个范围,但range
不是Range
,它是一个const Range
。 R
可能是一个range
,但R const
不是,所以您实际上并没有正确地限制这个 function。
正确的约束是:
template<typename Range>
requires std::ranges::range<Range const>
auto make_vector(Range const& range)
但这会限制您只能使用 const-iterable 范围(这是不必要的限制),然后需要您非常小心地在整个主体中使用Range const
(这很容易忘记)。
这两者都是为什么,对于范围,你会想要使用转发引用:
template<std::ranges::range Range>
auto make_vector(Range&& range)
这将正确限制您的 function 。
下一个:
using IteratorType = decltype(std::ranges::begin(std::declval<Range&>()));
using DerefType = decltype(*std::declval<IteratorType>());
using T = std::remove_cvref_t<DerefType>;
这些东西直接有类型特征:
using IteratorType = std::ranges::iterator_t<Range>;
using DerefType = std::iter_reference_t<IteratorType>;
或者:
using DerefType = std::ranges::range_reference_t<Range>;
但也因为你想要值类型,那就是(正如已经指出的那样):
using T = std::ranges::range_value_t<Range>;
请注意,值类型不一定只是删除了限定符的引用类型。
最后:
std::vector<T> retval;
for (auto const& x: range) {
retval.push_back(x);
}
return retval;
将元素转发到push_back
会更有效甚至更正确(即auto&& x
然后是FWD(x)
,而不是auto const& x
和x
)。
此外,您至少需要:
if constexpr (std::ranges::sized_range<Range>) {
retval.reserve(std::ranges::size(range));
}
因为如果我们有随时可用的大小,那么将分配减少到只有一个会很好。
最后,在 C++23 中, make_vector(r)
可以拼写为std::ranges::to<std::vector>(r)
。 这实现了我提到的分配优化,但还可以提高性能,因为vector
的内部构造可以避免不断检查是否需要额外分配(这是push_back
必须做的)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.