Skip to content

[SUGGESTION] optional-like API for raw-pointers (thanks to UFCS) #192

@filipsajdak

Description

@filipsajdak

Thanks to UFCS, we can create an API that will make working with pointers more like with std::optional. That can make it easier to avoid dereferencing null pointers. Also, it can help create more generic code that will work with pointers and std::optional.

int* nptr = nullptr;
int* ptr = new int(42);

main: () -> int = {
    std::cout << "ptr.has_value(): "  << std::boolalpha << ptr.has_value() << std::endl;
    std::cout << "nptr.has_value(): " << std::boolalpha << nptr.has_value() << std::endl;

    std::cout << "ptr.value(): "      << ptr.value() << std::endl;
    std::cout << "ptr.value_or(0): "  << ptr.value_or(0) << std::endl;
    std::cout << "nptr.value_or(0): " << nptr.value_or(0) << std::endl;

    ptr.swap(nptr); std::cout <<"\nptr.swap(nptr);\n" << std::endl;

    std::cout << "ptr.value_or(0): "  << ptr.value_or(0) << std::endl;
    std::cout << "nptr.value_or(0): " << nptr.value_or(0) << std::endl;
    
    nptr.reset(); std::cout <<"\nnptr.reset();\n" << std::endl;

    std::cout << "nptr.has_value(): " << std::boolalpha << nptr.has_value() << std::endl;

    nptr.emplace(123); std::cout <<"\nnptr.emplace(123);\n" << std::endl;

    std::cout << "nptr.value_or(0): " << nptr.value_or(0) << std::endl;

    std::cout << "ptr.emplace(9999): " << ptr.emplace(9999) << std::endl;

}

template < typename X >
    requires std::is_pointer_v<X>
constexpr bool has_value( X const& x ) noexcept {
    return bool(x);
}

template < typename X >
    requires std::is_pointer_v<X>
constexpr auto value( X& x ) -> decltype(*x) {
    if (!x)
        throw std::bad_optional_access();
    return *x;
}

template < typename X >
    requires std::is_pointer_v<X>
constexpr auto value( X const& x ) -> decltype(*x) {
    if (!x)
        throw std::bad_optional_access();
    return *x;
}

template< typename X, class U >
    requires std::is_pointer_v<X>
constexpr auto value_or( X const& x, U&& default_value ) -> CPP2_TYPEOF(*x) {
    if (!x)
        return std::forward<U>(default_value);
    return *x;
}

template< typename X, class U >
    requires std::is_pointer_v<X>
constexpr auto swap( X& x, U& other ) -> void {
    std::swap(x, other);
}

template < typename X >
    requires std::is_pointer_v<X>
constexpr auto reset( X& x ) -> void {
    if (x) {
        delete x;
        x = nullptr;
    }
}

template< typename X, class... Args >
    requires std::is_pointer_v<X>
auto emplace( X& x, Args&&... args ) -> decltype(*x) {
    if (x)
        delete x;
    using T = CPP2_TYPEOF(*x);
    x = new T(std::forward<Args>(args)...);
    return *x;
}

template< typename X, class U, class... Args >
    requires std::is_pointer_v<X>
auto emplace( X& x, std::initializer_list<U> ilist, Args&&... args ) -> decltype(*x) {
    if (x)
        delete x;
    using T = CPP2_TYPEOF(*x);
    x = new T(ilist, std::forward<Args>(args)...);
    return *x;
}

The above code will return:

ptr.has_value(): true
nptr.has_value(): false
ptr.value(): 42
ptr.value_or(0): 42
nptr.value_or(0): 0

ptr.swap(nptr);

ptr.value_or(0): 0
nptr.value_or(0): 42

nptr.reset();

nptr.has_value(): false

nptr.emplace(123);

nptr.value_or(0): 123
ptr.emplace(9999): 9999

We can also make overloads for smart pointers.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions