forked from OSchip/llvm-project
[libcxx] adds concept `std::common_reference_with`
Implements parts of: - P0898R3 Standard Library Concepts - P1754 Rename concepts to standard_case for C++20, while we still can Depends on D96657 Reviewed By: ldionne, Mordante, #libc Differential Revision: https://reviews.llvm.org/D96660
This commit is contained in:
parent
553cb6d473
commit
3f5438c46c
|
@ -173,6 +173,13 @@ concept convertible_to =
|
|||
static_cast<_To>(__f());
|
||||
};
|
||||
|
||||
// [concept.commonref]
|
||||
template<class _Tp, class _Up>
|
||||
concept common_reference_with =
|
||||
same_as<common_reference_t<_Tp, _Up>, common_reference_t<_Up, _Tp>> &&
|
||||
convertible_to<_Tp, common_reference_t<_Tp, _Up>> &&
|
||||
convertible_to<_Up, common_reference_t<_Tp, _Up>>;
|
||||
|
||||
// [concepts.arithmetic], arithmetic concepts
|
||||
template<class _Tp>
|
||||
concept integral = is_integral_v<_Tp>;
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++03, c++11, c++14, c++17
|
||||
// UNSUPPORTED: libcpp-no-concepts
|
||||
|
||||
// template<class From, class To>
|
||||
// concept common_reference_with;
|
||||
|
||||
#include <concepts>
|
||||
|
||||
template <class T, class U>
|
||||
constexpr bool CheckCommonReferenceWith() noexcept {
|
||||
static_assert(std::common_reference_with<T, U&>);
|
||||
static_assert(std::common_reference_with<T, const U&>);
|
||||
static_assert(std::common_reference_with<T, volatile U&>);
|
||||
static_assert(std::common_reference_with<T, const volatile U&>);
|
||||
static_assert(std::common_reference_with<T, U&&>);
|
||||
static_assert(std::common_reference_with<T, const U&&>);
|
||||
static_assert(std::common_reference_with<T, volatile U&&>);
|
||||
static_assert(std::common_reference_with<T, const volatile U&&>);
|
||||
static_assert(std::common_reference_with<T&, U&&>);
|
||||
static_assert(std::common_reference_with<T&, const U&&>);
|
||||
static_assert(std::common_reference_with<T&, volatile U&&>);
|
||||
static_assert(std::common_reference_with<T&, const volatile U&&>);
|
||||
static_assert(std::common_reference_with<const T&, U&&>);
|
||||
static_assert(std::common_reference_with<const T&, const U&&>);
|
||||
static_assert(std::common_reference_with<const T&, volatile U&&>);
|
||||
static_assert(std::common_reference_with<const T&, const volatile U&&>);
|
||||
static_assert(std::common_reference_with<volatile T&, U&&>);
|
||||
static_assert(std::common_reference_with<volatile T&, const U&&>);
|
||||
static_assert(std::common_reference_with<volatile T&, volatile U&&>);
|
||||
static_assert(std::common_reference_with<volatile T&, const volatile U&&>);
|
||||
static_assert(std::common_reference_with<const volatile T&, U&&>);
|
||||
static_assert(std::common_reference_with<const volatile T&, const U&&>);
|
||||
static_assert(std::common_reference_with<const volatile T&, volatile U&&>);
|
||||
static_assert(
|
||||
std::common_reference_with<const volatile T&, const volatile U&&>);
|
||||
|
||||
return std::common_reference_with<T, U>;
|
||||
}
|
||||
|
||||
namespace BuiltinTypes {
|
||||
// fundamental types
|
||||
static_assert(std::common_reference_with<void, void>);
|
||||
static_assert(CheckCommonReferenceWith<int, int>());
|
||||
static_assert(CheckCommonReferenceWith<int, long>());
|
||||
static_assert(CheckCommonReferenceWith<int, unsigned char>());
|
||||
#ifndef _LIBCPP_HAS_NO_INT128
|
||||
static_assert(CheckCommonReferenceWith<int, __int128_t>());
|
||||
#endif
|
||||
static_assert(CheckCommonReferenceWith<int, double>());
|
||||
|
||||
// arrays
|
||||
static_assert(CheckCommonReferenceWith<int[5], int[5]>());
|
||||
|
||||
// pointers (common with void*)
|
||||
static_assert(CheckCommonReferenceWith<int*, void*>());
|
||||
static_assert(CheckCommonReferenceWith<int*, const void*>());
|
||||
static_assert(CheckCommonReferenceWith<int*, volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<int*, const volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<const int*, void*>());
|
||||
static_assert(CheckCommonReferenceWith<const int*, const void*>());
|
||||
static_assert(CheckCommonReferenceWith<const int*, volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<const int*, const volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<volatile int*, void*>());
|
||||
static_assert(CheckCommonReferenceWith<volatile int*, const void*>());
|
||||
static_assert(CheckCommonReferenceWith<volatile int*, volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<volatile int*, const volatile void*>());
|
||||
static_assert(CheckCommonReferenceWith<const volatile int*, void*>());
|
||||
static_assert(CheckCommonReferenceWith<const volatile int*, const void*>());
|
||||
static_assert(CheckCommonReferenceWith<const volatile int*, volatile void*>());
|
||||
static_assert(
|
||||
CheckCommonReferenceWith<const volatile int*, const volatile void*>());
|
||||
|
||||
static_assert(CheckCommonReferenceWith<int (*)(), int (*)()>());
|
||||
static_assert(CheckCommonReferenceWith<int (*)(), int (*)() noexcept>());
|
||||
struct S {};
|
||||
static_assert(CheckCommonReferenceWith<int S::*, int S::*>());
|
||||
static_assert(CheckCommonReferenceWith<int S::*, const int S::*>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)(), int (S::*)()>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)(), int (S::*)() noexcept>());
|
||||
static_assert(
|
||||
CheckCommonReferenceWith<int (S::*)() const, int (S::*)() const>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)() const,
|
||||
int (S::*)() const noexcept>());
|
||||
static_assert(
|
||||
CheckCommonReferenceWith<int (S::*)() volatile, int (S::*)() volatile>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)() volatile,
|
||||
int (S::*)() volatile noexcept>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)() const volatile,
|
||||
int (S::*)() const volatile>());
|
||||
static_assert(CheckCommonReferenceWith<int (S::*)() const volatile,
|
||||
int (S::*)() const volatile noexcept>());
|
||||
|
||||
// nonsense
|
||||
static_assert(!std::common_reference_with<double, float*>);
|
||||
static_assert(!std::common_reference_with<int, int[5]>);
|
||||
static_assert(!std::common_reference_with<int*, long*>);
|
||||
static_assert(!std::common_reference_with<int*, unsigned int*>);
|
||||
static_assert(!std::common_reference_with<int (*)(), int (*)(int)>);
|
||||
static_assert(!std::common_reference_with<int S::*, float S::*>);
|
||||
static_assert(!std::common_reference_with<int (S::*)(), int (S::*)() const>);
|
||||
static_assert(!std::common_reference_with<int (S::*)(), int (S::*)() volatile>);
|
||||
static_assert(
|
||||
!std::common_reference_with<int (S::*)(), int (S::*)() const volatile>);
|
||||
static_assert(
|
||||
!std::common_reference_with<int (S::*)() const, int (S::*)() volatile>);
|
||||
static_assert(!std::common_reference_with<int (S::*)() const,
|
||||
int (S::*)() const volatile>);
|
||||
static_assert(!std::common_reference_with<int (S::*)() volatile,
|
||||
int (S::*)() const volatile>);
|
||||
} // namespace BuiltinTypes
|
||||
|
||||
namespace NoDefaultCommonReference {
|
||||
class T {};
|
||||
|
||||
static_assert(!std::common_reference_with<T, int>);
|
||||
static_assert(!std::common_reference_with<int, T>);
|
||||
static_assert(!std::common_reference_with<T, int[10]>);
|
||||
static_assert(!std::common_reference_with<T[10], int>);
|
||||
static_assert(!std::common_reference_with<T*, int*>);
|
||||
static_assert(!std::common_reference_with<T*, const int*>);
|
||||
static_assert(!std::common_reference_with<T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<const T*, int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, int*>);
|
||||
static_assert(!std::common_reference_with<const volatile T*, int*>);
|
||||
static_assert(!std::common_reference_with<const T*, const int*>);
|
||||
static_assert(!std::common_reference_with<const T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<const T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<const T*, const int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, const int*>);
|
||||
static_assert(!std::common_reference_with<const volatile T*, const int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, const int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<const T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<const volatile T*, volatile int*>);
|
||||
static_assert(!std::common_reference_with<const volatile T*, const int*>);
|
||||
static_assert(!std::common_reference_with<const volatile T*, volatile int*>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<const T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<volatile T*, const volatile int*>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T*, const volatile int*>);
|
||||
static_assert(!std::common_reference_with<T&, int&>);
|
||||
static_assert(!std::common_reference_with<T&, const int&>);
|
||||
static_assert(!std::common_reference_with<T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&, int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, int&>);
|
||||
static_assert(!std::common_reference_with<const T&, const int&>);
|
||||
static_assert(!std::common_reference_with<const T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, const int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, volatile int&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const volatile int&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<T&, int&&>);
|
||||
static_assert(!std::common_reference_with<T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&, volatile int&&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&, const volatile int&&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<T&&, int&>);
|
||||
static_assert(!std::common_reference_with<T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, volatile int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, const int&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, volatile int&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const volatile int&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&&, const volatile int&>);
|
||||
static_assert(!std::common_reference_with<T&&, int&&>);
|
||||
static_assert(!std::common_reference_with<T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<T&&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, const int&&>);
|
||||
static_assert(!std::common_reference_with<const volatile T&&, volatile int&&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<const T&&, const volatile int&&>);
|
||||
static_assert(!std::common_reference_with<volatile T&&, const volatile int&&>);
|
||||
static_assert(
|
||||
!std::common_reference_with<const volatile T&&, const volatile int&&>);
|
||||
} // namespace NoDefaultCommonReference
|
||||
|
||||
struct BadBasicCommonReference {
|
||||
// This test is ill-formed, NDR. If it ever blows up in our faces: that's a good thing.
|
||||
// In the meantime, the test should be included. If compiler support is added, then an include guard
|
||||
// should be placed so the test doesn't get deleted.
|
||||
operator int() const;
|
||||
operator int&();
|
||||
};
|
||||
static_assert(std::convertible_to<BadBasicCommonReference, int>);
|
||||
static_assert(std::convertible_to<BadBasicCommonReference, int&>);
|
||||
|
||||
namespace std {
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<BadBasicCommonReference, int, X, Y> {
|
||||
using type = BadBasicCommonReference&;
|
||||
};
|
||||
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<int, BadBasicCommonReference, X, Y> {
|
||||
using type = int&;
|
||||
};
|
||||
} // namespace std
|
||||
static_assert(!std::common_reference_with<BadBasicCommonReference, int>);
|
||||
|
||||
struct StructNotConvertibleToCommonReference {
|
||||
explicit(false) StructNotConvertibleToCommonReference(int);
|
||||
};
|
||||
static_assert(std::convertible_to<int, StructNotConvertibleToCommonReference>);
|
||||
|
||||
namespace std {
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<StructNotConvertibleToCommonReference, int, X,
|
||||
Y> {
|
||||
using type = int&;
|
||||
};
|
||||
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<int, StructNotConvertibleToCommonReference, X,
|
||||
Y> {
|
||||
using type = int&;
|
||||
};
|
||||
} // namespace std
|
||||
static_assert(
|
||||
!std::common_reference_with<StructNotConvertibleToCommonReference, int>);
|
||||
|
||||
struct IntNotConvertibleToCommonReference {
|
||||
operator int&() const;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<IntNotConvertibleToCommonReference, int, X, Y> {
|
||||
using type = int&;
|
||||
};
|
||||
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<int, IntNotConvertibleToCommonReference, X, Y> {
|
||||
using type = int&;
|
||||
};
|
||||
} // namespace std
|
||||
static_assert(
|
||||
!std::common_reference_with<StructNotConvertibleToCommonReference, int>);
|
||||
|
||||
struct HasCommonReference {
|
||||
explicit(false) HasCommonReference(int);
|
||||
operator int&() const;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<HasCommonReference, int, X, Y> {
|
||||
using type = int&;
|
||||
};
|
||||
|
||||
template <template <class> class X, template <class> class Y>
|
||||
struct basic_common_reference<int, HasCommonReference, X, Y> {
|
||||
using type = int&;
|
||||
};
|
||||
} // namespace std
|
||||
static_assert(!std::common_reference_with<HasCommonReference, int>);
|
||||
static_assert(std::common_reference_with<HasCommonReference, int&>);
|
||||
|
||||
int main(int, char**) { return 0; }
|
Loading…
Reference in New Issue