-
Notifications
You must be signed in to change notification settings - Fork 266
Closed
Labels
Description
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.
jcanizales