Created
December 16, 2012 20:40
-
-
Save fpelliccioni/4312663 to your computer and use it in GitHub Desktop.
C++ Safe Dereferencing Nullable References Proposal
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <memory> | |
#include <cstddef> //std::nullptr_t; | |
template <typename T> | |
class safe_ref | |
{ | |
public: | |
typedef T type; | |
typedef T& reference; | |
explicit safe_ref( std::nullptr_t ) | |
: t_( nullptr ) | |
{} | |
explicit safe_ref() | |
: t_( nullptr ) | |
{} | |
explicit safe_ref(T& t) | |
: t_( std::addressof(t) ) | |
{} | |
template < typename Y > | |
explicit safe_ref( Y& t ) | |
: t_( std::addressof(t) ) | |
{} | |
template < typename Y > | |
safe_ref( safe_ref<Y> const& r ) | |
: t_( r.t_ ) | |
{} | |
template <typename Func> | |
void use ( Func f ) const | |
{ | |
T* local_ptr = t_; | |
if ( local_ptr != nullptr ) | |
{ | |
f( *t_ ); //side note: how to know if f(...) is const? | |
} | |
} | |
template <typename Func, typename FuncElse> | |
void use ( Func f, FuncElse fe ) const | |
{ | |
T* local_ptr = t_; | |
if ( local_ptr != nullptr ) | |
{ | |
f( *t_ ); //side note: how to know if f(...) is const? | |
} | |
else | |
{ | |
fe(); | |
} | |
} | |
safe_ref& operator=( std::nullptr_t ) | |
{ | |
t_ = nullptr; | |
} | |
safe_ref& operator=( T& t ) | |
{ | |
t_ = std::addressof(t); | |
} | |
private: | |
bool is_initialized() const | |
{ | |
return t_ != nullptr; | |
} | |
private: | |
template <typename Y> friend class safe_ref; | |
T* t_; | |
}; | |
template <typename T> | |
inline safe_ref<T> const ref(T& t) | |
{ | |
return safe_ref<T>(t); | |
} | |
template <typename T> | |
inline safe_ref<T const> const cref(T const& t) | |
{ | |
return safe_ref<T const>(t); | |
} | |
#define IF(_local_, _ref_, _if_code_, _else_code_) \ | |
_ref_.use( [&] ( typename decltype(_ref_)::reference _local_ ) { \ | |
_if_code_ \ | |
}, \ | |
[&] { \ | |
_else_code_ \ | |
}); | |
//---------------------------------------------------------------------------- | |
// Usage | |
//---------------------------------------------------------------------------- | |
#include <iostream> | |
#include <string> | |
struct A | |
{ | |
void doit() const | |
{ | |
std::cout << "A::doit: " << i_ << "\n"; | |
} | |
int i_ = 99; | |
}; | |
void f( safe_ref<A> ref ) | |
{ | |
IF( local, ref, | |
{ | |
local.doit(); | |
}, | |
{ | |
std::cout << "is nullptr\n"; | |
}) | |
} | |
int main() | |
{ | |
A a; | |
safe_ref<A> r; | |
f(r); | |
r = a; | |
f(r); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment