range_value_t 用于引用类型

Ziz*_*Tai 6 c++ c++20

我正在玩 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总是给我一个腐烂的类型吗?

Bar*_*rry 9

应该range_value_t总是给我一个腐烂的类型吗?

迭代器value_type(以及范围)的 应该始终是cv未限定的类型,是的。这就是模型的工作方式。据我所知,标准库中并没有真正指定这一点,但是您可以看到 ofvalue_typeT*( remove_cv_t<T>[ iterators.iterator.traits]/5value_type ) 或者我们获取oftransform_view迭代器的方式是通过执行remove_cvref_ton类型reference[range.transform.iterator])。

reference另一方面,是当您取消引用迭代器时获得的类型 - 从字面上看decltype(*it)。不幸的是,这个名称很容易混淆,因为reference它不一定是一种语言类型。

例如,int*基本上是最简单的迭代器:its value_typeis intwhile its referenceis int&。类似地,对于int const*value_type是相同的(仍然int),而reference变化的是(int const&)。