我正在玩 C++ 20 范围并注意到一些奇怪的东西(可在https://gcc.godbolt.org/z/4Ycxn88qa重现):
#include <vector>
#include <utility>
#include <string>
#include <ranges>
#include <type_traits>
int main()
{
using KV = std::pair<std::string, std::string>;
std::vector<KV> v;
auto r = v | std::views::filter([](const KV& kv) { return kv.first == "foo"; })
| std::views::transform([](const KV& kv) -> const std::string& { return kv.second; });
for (auto&& val : r) {
static_assert(std::is_same_v<decltype(val), const std::string&>);
}
using R = decltype(r);
using Elem = std::ranges::range_value_t<R>;
static_assert(std::is_same_v<Elem, std::string>); // success
static_assert(std::is_same_v<Elem, const std::string&>); // error
}
Run Code Online (Sandbox Code Playgroud)
我预计最后一个static_assert
会成功,倒数第二个会失败,但事实恰恰相反。为什么?
更新:显然range_reference_t
给了我我需要的东西:
static_assert(std::is_same_v<std::ranges::range_reference_t<R>, const std::string&>); // ok
Run Code Online (Sandbox Code Playgroud)
应该range_value_t
总是给我一个腐烂的类型吗?
应该
range_value_t
总是给我一个腐烂的类型吗?
迭代器value_type
(以及范围)的 应该始终是cv未限定的类型,是的。这就是模型的工作方式。据我所知,标准库中并没有真正指定这一点,但是您可以看到 ofvalue_type
是T*
( remove_cv_t<T>
[ iterators.iterator.traits]/5value_type
) 或者我们获取oftransform_view
迭代器的方式是通过执行remove_cvref_t
on类型reference
([range.transform.iterator])。
reference
另一方面,是当您取消引用迭代器时获得的类型 - 从字面上看decltype(*it)
。不幸的是,这个名称很容易混淆,因为reference
它不一定是一种语言类型。
例如,int*
基本上是最简单的迭代器:its value_type
is int
while its reference
is int&
。类似地,对于int const*
,value_type
是相同的(仍然int
),而reference
变化的是(int const&
)。