Class constrained_type

Synopsis

#include <include/type_safe/constrained_type.hpp>

template <typename T, typename Constraint, class Verifier = assertion_verifier>
class constrained_type : Constraint

Description

A value of type T that always fulfills the predicate Constraint.

The Constraint is checked by the Verifier. The Constraint can also provide a nested template is_valid<T> to statically check types. Those will be checked regardless of the Verifier.

If T is const, the modify() function will not be available, you can only modify the type by assigning a completely new value to it. \requires T must not be a reference, Constraint must be a moveable, non-final class where no operation throws, and Verifier must provide a static function [const] T[&] verify(const T&, const Predicate&). The return value is stored and it must always fulfill the predicate. It also requires that no const operation on T may modify it in a way that the predicate isn't fulfilled anymore. \notes Additional requirements of the Constraint depend on the Verifier used. If not stated otherwise, a Verifier in this library requires that the Constraint is a Predicate for T.

Inheritance

Ancestors: Constraint

Methods

constrained_type overload\effects Creates it giving it a valid value and a predicate
constrained_type overload\group value_ctor
constrained_type overload\exclude
constrained_type overload\effects Copies the value and predicate of other.
~constrained_type\effects Destroys the value.
get_constraintReturns: The predicate that determines validity.
get_valueReturns: A const reference to the stored value.
modifyReturns: A proxy object to provide verified write-access to the stored value
operator*Dereference operator.
operator->Member access operator.
operator= overload\effects Same as assigning constrained_type(other, get_constraint()).release() to the stored value
operator= overload\group assign_value
operator= overload\exclude
operator= overload\effects Copies the value and predicate from other.
release\effects Moves the stored value out of the constrained_type, it will not be checked further.

Source

Lines 101-261 in include/type_safe/constrained_type.hpp.

template <typename T, typename Constraint, class Verifier = assertion_verifier>
class constrained_type : Constraint
{
public:
    using value_type           = typename std::remove_cv<T>::type;
    using constraint_predicate = Constraint;

    /// \effects Creates it giving it a valid `value` and a `predicate`.
    /// The `value` will be copied(1)/moved(2) and verified.
    /// \throws Anything thrown by the copy(1)/move(2) constructor of `value_type`
    /// or the `Verifier` if the `value` is invalid.
    /// \group value_ctor
    explicit constexpr constrained_type(const value_type&    value,
                                        constraint_predicate predicate = {})
    : Constraint(std::move(predicate)), value_(Verifier::verify(value, get_constraint()))
    {}

    /// \group value_ctor
    explicit constexpr constrained_type(
        value_type&&         value,
        constraint_predicate predicate
        = {}) noexcept(std::is_nothrow_constructible<value_type>::
                           value&& noexcept(Verifier::verify(std::move(value),
                                                             std::move(predicate))))
    : Constraint(std::move(predicate)), value_(Verifier::verify(std::move(value), get_constraint()))
    {}

    /// \exclude
    template <typename U,
              typename
              = typename std::enable_if<!detail::is_valid<constraint_predicate, U>::value>::type>
    constrained_type(U) = delete;

    /// \effects Copies the value and predicate of `other`.
    /// \throws Anything thrown by the copy constructor of `value_type`.
    /// \requires `Constraint` must be copyable.
    constexpr constrained_type(const constrained_type& other)
    : Constraint(other), value_(other.debug_verify())
    {}

    /// \effects Destroys the value.
    ~constrained_type() noexcept = default;

    /// \effects Same as assigning `constrained_type(other, get_constraint()).release()` to the
    /// stored value. It will invoke copy(1)/move(2) constructor followed by move assignment
    /// operator. \throws Anything thrown by the copy(1)/move(2) constructor or move assignment
    /// operator of `value_type`, or the `Verifier` if the `value` is invalid. If the `value` is
    /// invalid, nothing will be changed. \requires `Constraint` must be copyable. \group
    /// assign_value
    TYPE_SAFE_CONSTEXPR14 constrained_type& operator=(const value_type& other)
    {
        constrained_type tmp(other, get_constraint());
        value_ = std::move(tmp).release();
        return *this;
    }

    /// \group assign_value
    TYPE_SAFE_CONSTEXPR14 constrained_type& operator=(value_type&& other) noexcept(
        std::is_nothrow_move_assignable<value_type>::value&& noexcept(
            Verifier::verify(std::move(other), std::declval<Constraint&>())))
    {
        constrained_type tmp(std::move(other), get_constraint());
        value_ = std::move(tmp).release();
        return *this;
    }

    /// \exclude
    template <typename U,
              typename
              = typename std::enable_if<!detail::is_valid<constraint_predicate, U>::value>::type>
    constrained_type& operator=(U) = delete;

    /// \effects Copies the value and predicate from `other`.
    /// \throws Anything thrown by the copy assignment operator of `value_type`.
    /// \requires `Constraint` must be copyable.
    TYPE_SAFE_CONSTEXPR14 constrained_type& operator=(const constrained_type& other)
    {
        constrained_type tmp(other);
        swap(*this, tmp);
        return *this;
    }

    /// \effects Swaps the value and predicate of a `a` and `b`.
    /// \throws Anything thrown by the swap function of `value_type`.
    /// \requires `Constraint` must be swappable.
    friend TYPE_SAFE_CONSTEXPR14 void swap(constrained_type& a, constrained_type& b) noexcept(
        detail::is_nothrow_swappable<value_type>::value)
    {
        a.debug_verify();
        b.debug_verify();

        using std::swap;
        swap(a.value_, b.value_);
        swap(static_cast<Constraint&>(a), static_cast<Constraint&>(b));
    }

    /// \returns A proxy object to provide verified write-access to the stored value.
    /// \notes This function does not participate in overload resolution if `T` is `const`.
    template <typename Dummy = T,
              typename       = typename std::enable_if<!std::is_const<Dummy>::value>::type>
    constrained_modifier<T, Constraint, Verifier> modify() noexcept
    {
        debug_verify();
        return constrained_modifier<T, Constraint, Verifier>(*this);
    }

    /// \effects Moves the stored value out of the `constrained_type`,
    /// it will not be checked further.
    /// \returns An rvalue reference to the stored value.
    /// \notes After this function is called, the object must not be used anymore
    /// except as target for assignment or in the destructor.
    TYPE_SAFE_CONSTEXPR14 value_type&& release() TYPE_SAFE_RVALUE_REF noexcept
    {
        debug_verify();
        return std::move(value_);
    }

    /// Dereference operator.
    /// \returns A `const` reference to the stored value.
    constexpr const value_type& operator*() const noexcept
    {
        return get_value();
    }

    /// Member access operator.
    /// \returns A `const` pointer to the stored value.
    constexpr const value_type* operator->() const noexcept
    {
        return std::addressof(get_value());
    }

    /// \returns A `const` reference to the stored value.
    constexpr const value_type& get_value() const noexcept
    {
        return debug_verify();
    }

    /// \returns The predicate that determines validity.
    constexpr const constraint_predicate& get_constraint() const noexcept
    {
        return *this;
    }

private:
    constexpr const value_type& debug_verify() const noexcept
    {
#if TYPE_SAFE_ENABLE_ASSERTIONS
        return Verifier::verify(value_, get_constraint()), value_;
#else
        return value_;
#endif
    }

    TYPE_SAFE_CONSTEXPR14 value_type& get_non_const() noexcept
    {
        return value_;
    }

    value_type value_;
    friend constrained_modifier<T, Constraint, Verifier>;
};





Add Discussion as Guest

Log in