153 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// <functional>10//11// UNSUPPORTED: c++03, c++11, c++14, c++1712//13// common_reference specializations for reference_wrapper14 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.440template <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 off61static_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 convertibles69struct 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 P2655R392 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 on143// 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 of149static_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