繁体   English   中英

如何获取 C++20 std::ranges 范围内值的类型?

[英]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& xx )。


此外,您至少需要:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM