나무모에 미러 (일반/밝은 화면)
최근 수정 시각 : 2024-06-01 06:51:12

C++/표준 라이브러리/concepts

파일:상위 문서 아이콘.svg   상위 문서: C++/표준 라이브러리
1. 개요2. 설명3. 예제

1. 개요

# 제약조건

2. 설명

3. 예제


==# 모듈 요약 코드 #==
#!syntax cpp
namespace std
{
    // language-related concepts
    template<class T, class U>
    concept same_as = is_same_v<T, U> && is_same_v<U, T>;

    template<class Derived, class Base>
    concept derived_from = is_base_of_v<Base, Derived> && is_convertible_v<const volatile Derived*, const volatile Base*>;

    template<class From, class To>
    concept convertible_to = is_convertible_v<From, To>
    && requires(From (&from)())
    {
        static_cast<To>(from()); // std::declval<From&>()
    };

    template<class T, class U>
    concept common_reference_with = same_as<common_reference_t<T, U>, common_reference_t<U, T>>
    && convertible_to<T, common_reference_t<T, U>>
    && convertible_to<U, common_reference_t<T, U>>;

    template<class T, class U>
    concept common_with =  same_as<common_type_t<T, U>, common_type_t<U, T>>
    && requires
    {
        static_cast<common_type_t<T, U>>(declval<T>());
        static_cast<common_type_t<T, U>>(declval<U>());
    }
    && common_reference_with<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>
    && common_reference_with<add_lvalue_reference_t<common_type_t<T, U>>, common_reference_t<add_lvalue_reference_t<const T>, add_lvalue_reference_t<const U>>>;

    // arithmetic concepts
    template<class T>
    concept integral = is_integral_v<T>;
    template<class T>
    concept signed_integral = integral<T> && is_signed_v<T>;
    template<class T>
    concept unsigned_integral = integral<T> && !signed_integral<T>;
    template<class T>
    concept floating_point = is_floating_point_v<T>;

    template<class LHS, class RHS>
    concept assignable_from = is_lvalue_reference_v<LHS>
    && common_reference_with<const remove_reference_t<LHS>&, const remove_reference_t<RHS>&>
    && requires(LHS lhs, RHS&& rhs)
    {
        { lhs = std::forward<RHS>(rhs) } -> same_as<LHS>;
    }

    namespace ranges
    {
        inline namespace /* unspecified */
        {
            inline constexpr /* unspecified */ swap = /* unspecified */;
        }
    }

    template<class T>
    concept swappable = requires(T& a, T& b) { ranges::swap(a, b); };
    template<class T, class U>
    concept swappable_with = common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>
    && requires(T&& t, U&& u)
    {
        ranges::swap(std::forward<T>(t), std::forward<T>(t));
        ranges::swap(std::forward<U>(u), std::forward<U>(u));
        ranges::swap(std::forward<T>(t), std::forward<U>(u));
        ranges::swap(std::forward<U>(u), std::forward<T>(t));
    };

    template<class T>
    concept destructible = is_nothrow_destructible_v<T>;

    template<class T, class... Args>
    concept constructible_from = destructible<T> && is_constructible_v<T, Args...>;

    template<class T>
    concept default_initializable = /* --- */;

    template<class T>
    concept move_constructible = constructible_from<T, T> && convertible_to<T, T>;

    template<class T>
    concept copy_constructible = move_constructible<T>
    && constructible_from<T, T&> && convertible_to<T&, T>
    && constructible_from<T, const T&> && convertible_to<const T&, T>
    && constructible_from<T, const T> && convertible_to<const T, T>;

    // comparison concepts
    template<class T, class U>
    concept __WeaklyEqualityComparableWith = // exposition only
    requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u)
    {
        { t == u } -> boolean-testable;
        { t != u } -> boolean-testable;
        { u == t } -> boolean-testable;
        { u != t } -> boolean-testable;
    };
 
    template<class T>
    concept equality_comparable = __WeaklyEqualityComparableWith<T, T>;
    template<class T>
    concept equality_comparable = /* see description */;
    template<class T, class U>
    concept equality_comparable_with = equality_comparable<T> && equality_comparable<U>
    && common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>
    && equality_comparable<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
    && __WeaklyEqualityComparableWith<T, U>;

    template<class T>
    concept totally_ordered = equality_comparable<T>
    && requires(const remove_reference_t<T>& a, const remove_reference_t<T>& b)
    {
        { a <  b } -> boolean-testable;
        { a >  b } -> boolean-testable;
        { a <= b } -> boolean-testable;
        { a >= b } -> boolean-testable;
    };
    template<class T, class U>
    concept totally_ordered_with = totally_ordered<T> && totally_ordered<U>
    && common_reference_with<const remove_reference_t<T>&, const remove_reference_t<U>&>
    && totally_ordered<common_reference_t<const remove_reference_t<T>&, const remove_reference_t<U>&>>
    && equality_comparable_with<T, U>
    && requires(const remove_reference_t<T>& t, const remove_reference_t<U>& u)
    {
        { t <  u } -> boolean-testable;
        { t >  u } -> boolean-testable;
        { t <= u } -> boolean-testable;
        { t >= u } -> boolean-testable;
        { u <  t } -> boolean-testable;
        { u >  t } -> boolean-testable;
        { u <= t } -> boolean-testable;
        { u >= t } -> boolean-testable;
    };

    // object concepts
    template<class T>
    concept movable = is_object_v<T> && move_constructible<T>
    && assignable_from<T&, T> && swappable<T>;
    template<class T>
    concept copyable = copy_constructible<T> && movable<T> && assignable_from<T&, T&>
    && assignable_from<T&, const T&> && assignable_from<T&, const T>;
    template<class T>
    concept semiregular = copyable<T> && default_initializable<T>;
    template<class T>
    concept regular = semiregular<T> && equality_comparable<T>;
 
    // callable concepts
    template<class F, class... Args>
    concept invocable = requires(F&& f, Args&&... args)
    {
         std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
    };

    template<class F, class... Args>
    concept regular_invocable = invocable<F, Args...>;

    template<class F, class... Args>
    concept predicate = regular_invocable<F, Args...> && boolean-testable<invoke_result_t<F, Args...>>;

    template<class R, class T, class U>
    concept relation = predicate<R, T, T> && predicate<R, U, U> && predicate<R, T, U> && predicate<R, U, T>;

    template<class R, class T, class U>
    concept equivalence_relation = relation<R, T, U>;

    template<class R, class T, class U>
    concept strict_weak_order = relation<R, T, U>;
}