Reputation: 6616
I was playing with C++ 20 ranges and noticed something weird (reproducible at 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
}
I expected the last static_assert
to succeed and the second to last to fail, but the reverse is true. Why?
UPDATE: Apparently range_reference_t
gives me what I need:
static_assert(std::is_same_v<std::ranges::range_reference_t<R>, const std::string&>); // ok
Is range_value_t
supposed to always give me a decayed type?
Upvotes: 7
Views: 1557
Reputation: 303057
Is
range_value_t
supposed to always give me a decayed type?
The value_type
of an iterator (and, consequently, a range) should always be a cv-unqualified type, yes. That's just the way that the model works. This isn't really specified in the standard library anywhere to my knowledge, but you can see that the value_type
of T*
is remove_cv_t<T>
([iterators.iterator.traits]/5) or that the way we get the value_type
of transform_view
's iterators is by doing a remove_cvref_t
on the reference
type ([range.transform.iterator]).
reference
, on the other hand, is the type that you get when you dereference the iterator - literally decltype(*it)
. Unfortunately, this one is confusingly named because reference
is not necessarily a language type.
For instance, int*
is basically the simplest iterator: its value_type
is int
while its reference
is int&
. Similarly, for int const*
, the value_type
is the same (still int
) while the reference
changes (to int const&
).
Upvotes: 10