See the code below (also here https://www.godbolt.org/z/hvnvEv1ar). The code fails to compile if I uncomment the constraint for either rng
or pair
. I feel like I am missing something trivial, but I can't figure out why the constraint is not satisfied.
#include <vector>
#include <ranges>
#include <utility>
template <typename T>
struct is_reference_wrapper : std::false_type {};
template <typename T>
struct is_reference_wrapper<std::reference_wrapper<T>> : std::true_type {};
template <typename T>
inline constexpr bool is_reference_wrapper_v = is_reference_wrapper<T>::value;
template <typename T>
concept ReferenceWrapper = is_reference_wrapper_v<T>;
template <typename T>
concept ReferenceWrapperPair = requires(const T& t) {
{ t.first } -> ReferenceWrapper;
{ t.second } -> ReferenceWrapper;
};
template <typename T>
concept ReferenceWrapperPairRange =
std::ranges::range<T> && ReferenceWrapperPair<std::ranges::range_value_t<T>>;
int main()
{
std::vector<std::pair<int, int>> v{ {1,2}, {3,4}, {5,6} };
auto fn = [](std::pair<int, int>& val) {
return std::pair{std::reference_wrapper<int>{val.first}, std::reference_wrapper<int>{val.second} };
};
/* ReferenceWrapperPairRange */ auto rng = v | std::views::transform(fn);
/* ReferenceWrapperPair */ auto pair = *(rng.begin());
ReferenceWrapper auto first = pair.first;
ReferenceWrapper auto second = pair.second;
return 0;
}
CodePudding user response:
The compound requirements { expression } -> type-constraint
requires that decltype((expression))
must satisfy the constraints imposed by type-constraint
, since decltype((t.first))
will be treated as an ordinary lvalue expression, it will result in a const lvalue reference type.
You might want to use C 23 auto(x)
to get the decay type
template <typename T>
concept ReferenceWrapperPair = requires(const T& t) {
{ auto(t.first) } -> ReferenceWrapper;
{ auto(t.second) } -> ReferenceWrapper;
};
Or change ReferenceWrapper
concept to:
template <typename T>
concept ReferenceWrapper = is_reference_wrapper_v<std::remove_cvref_t<T>>;