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?