1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9// <functional>
10//
11// UNSUPPORTED: c++03, c++11, c++14, c++17
12//
13// common_reference specializations for reference_wrapper
14
15#include <concepts>
16#include <functional>
17#include <type_traits>
18
19template <class T>
20concept HasType = requires { typename T::type; };
21
22template <class Result, class T1, class T2>
23concept check_XY = std::same_as<Result, std::common_reference_t<T1, T2>>;
24
25template <class Result, class T1, class T2>
26concept check_YX = std::same_as<Result, std::common_reference_t<T2, T1>>;
27
28template <class Result, class T1, class T2>
29concept check = check_XY<Result, T1, T2> && check_YX<Result, T1, T2>;
30
31template <class T1, class T2>
32concept check_none_XY = !HasType<std::common_reference<T1, T2>>;
33template <class T1, class T2>
34concept check_none_YX = !HasType<std::common_reference<T2, T1>>;
35
36template <class T1, class T2>
37concept check_none = check_none_XY<T1, T2> && check_none_YX<T1, T2>;
38
39// https://eel.is/c++draft/meta.trans#other-2.4
40template <class X, class Y>
41using CondRes = decltype(false ? std::declval<X (&)()>()() : std::declval<Y (&)()>()());
42
43template <class X, class Y>
44struct Ternary {};
45
46template <class X, class Y>
47 requires requires() { typename CondRes<X, Y>; }
48struct Ternary<X, Y> {
49 using type = CondRes<X, Y>;
50};
51template <class X, class Y>
52using Ternary_t = typename Ternary<X, Y>::type;
53
54template <class T>
55using Ref = std::reference_wrapper<T>;
56
57using std::common_reference_t;
58using std::same_as;
59
60// clang-format off
61static_assert(check<int & , Ref<int >, int & >);
62static_assert(check<int const&, Ref<int >, int const& >);
63static_assert(check<int const&, Ref<int const>, int & >);
64static_assert(check<int const&, Ref<int const>, int const& >);
65static_assert(check<int&, Ref<int> const&, int& >);
66static_assert(check<const volatile int&, Ref<const volatile int>, const volatile int&>);
67
68// derived-base and implicit convertibles
69struct B {};
70struct D : B {};
71struct C {
72 operator B&() const;
73};
74
75static_assert(check<B& , Ref<B>, D & >);
76static_assert(check<B const&, Ref<B>, D const&>);
77static_assert(check<B const&, Ref<B const>, D const&>);
78
79static_assert(check<B& , Ref<D>, B & >);
80static_assert(check<B const&, Ref<D>, B const&>);
81static_assert(check<B const&, Ref<D const>, B const&>);
82
83static_assert(std::same_as<B&, CondRes<Ref<D>, B&>>);
84static_assert(std::same_as<B const&, CondRes<Ref<D>, B const &>>);
85static_assert(std::same_as<B const&, CondRes<Ref<D const>, B const&>>);
86
87static_assert( check<B& , Ref<B> , C& >);
88static_assert( check<B& , Ref<B> , C >);
89static_assert( check<B const& , Ref<B const>, C >);
90static_assert(!check<B& , Ref<C> , B& >); // Ref<C> cannot be converted to B&
91static_assert( check<B& , Ref<B> , C const&>); // was const B& before P2655R3
92
93
94using Ri = Ref<int>;
95using RRi = Ref<Ref<int>>;
96using RRRi = Ref<Ref<Ref<int>>>;
97static_assert(check<Ri&, Ri&, RRi>);
98static_assert(check<RRi&, RRi&, RRRi>);
99static_assert(check<Ri, Ri, RRi>);
100static_assert(check<RRi, RRi, RRRi>);
101
102static_assert(check_none<int&, RRi>);
103static_assert(check_none<int, RRi>);
104static_assert(check_none<int&, RRRi>);
105static_assert(check_none<int, RRRi>);
106
107static_assert(check_none<Ri&, RRRi>);
108static_assert(check_none<Ri, RRRi>);
109
110
111template <typename T>
112struct Test {
113 // Check that reference_wrapper<T> behaves the same as T& in common_reference.
114
115 using R1 = common_reference_t<T&, T&>;
116 using R2 = common_reference_t<T&, T const&>;
117 using R3 = common_reference_t<T&, T&&>;
118 using R4 = common_reference_t<T&, T const&&>;
119 using R5 = common_reference_t<T&, T>;
120
121 static_assert(same_as<R1, common_reference_t<Ref<T>, T&>>);
122 static_assert(same_as<R2, common_reference_t<Ref<T>, T const&>>);
123 static_assert(same_as<R3, common_reference_t<Ref<T>, T&&>>);
124 static_assert(same_as<R4, common_reference_t<Ref<T>, T const&&>>);
125 static_assert(same_as<R5, common_reference_t<Ref<T>, T>>);
126
127 // commute:
128 static_assert(same_as<R1, common_reference_t<T&, Ref<T>>>);
129 static_assert(same_as<R2, common_reference_t<T const&, Ref<T>>>);
130 static_assert(same_as<R3, common_reference_t<T&&, Ref<T>>>);
131 static_assert(same_as<R4, common_reference_t<T const&&, Ref<T>>>);
132 static_assert(same_as<R5, common_reference_t<T, Ref<T>>>);
133
134 // reference qualification of reference_wrapper is irrelevant
135 static_assert(same_as<R1, common_reference_t<Ref<T>&, T&>>);
136 static_assert(same_as<R1, common_reference_t<Ref<T> , T&>>);
137 static_assert(same_as<R1, common_reference_t<Ref<T> const&, T&>>);
138 static_assert(same_as<R1, common_reference_t<Ref<T>&&, T&>>);
139 static_assert(same_as<R1, common_reference_t<Ref<T> const&&, T&>>);
140};
141
142// clang-format on
143// Instantiate above checks:
144template struct Test<int>;
145template struct Test<std::reference_wrapper<int>>;
146
147// reference_wrapper as both args is unaffected.
148// subject to simple first rule of
149static_assert(check<Ref<int>&, Ref<int>&, Ref<int>&>);
150
151// double wrap is unaffected.
152static_assert(check<Ref<int>&, Ref<Ref<int>>, Ref<int>&>);
153

source code of libcxx/test/std/utilities/function.objects/refwrap/common_reference.compile.pass.cpp