For a little less typing, you might consider something like gsl::not_null<Foo *>
in place of std::reference_wrapper<Foo>
(note the addition of the pointer to the templated type in gsl::not_null vs std::reference_wrapper). Then you could do something like (*ret)->bar()
or (**ret).bar()
. There is more information about the comparison of those two wrapper types in another question.
Note that most compilers implement references as pointers anyway, so the "extra" indirection still happens "under the hood", it's just done for you by the compiler. Thus, this should be primarily a question of typing and clarity rather than performance. In particular, since reference_wrapper<Foo>
and gsl::not_null<Foo *>
should both be trivially copyable and trivially destructible, you shouldn't be prevented from passing them in registers the way that you might with unique_ptr.
If you're unable or disinclined to use gsl specifically, you could write a similar wrapper class yourself:
- Use the constructors to enforce the invariant that a private member raw pointer "
T *
" is never null. To support polymorphism you probably want to allow constructing a "not_null<T>
" with a "U &
" where std::is_convertible<U *, T *>::value
is true. Copy constructor and destructor should be trivial.
- Add some method(s) -- probably at least inline dereference operator(s), but up to you -- to dereference the private member pointer
- Optionally add implicit or explicit conversion operators to reference and/or raw pointer
Example:
#include <type_traits>
// for std::addressof, unless you don't want to support
// classes with overloaded operator&
#include <memory>
namespace stack_overflow_answer {
template<typename T>
class non_null
{
T * raw;
public:
using pointer = T *;
using element_type = T;
using reference = T &;
// defining our own constructor
// already deletes the default constructor,
// but this makes it obvious that we did so on purpose
non_null() = delete;
// std::addressof is only constexpr since c++17,
// so for older compilers, either get rid of constexpr
// or give up supporting classes that overload operator&
// and replace std::addressof with &
constexpr non_null(reference t_ref) noexcept
: raw(std::addressof(t_ref))
{}
// construct from other types if pointer converts
template<
typename U,
typename Enable = typename std::enable_if<
std::is_convertible<U *, T *>::value
&& !std::is_same<U *, T *>::value
>::type
> constexpr non_null(U & convertible_ref) noexcept
: raw(std::addressof(convertible_ref))
{}
non_null(non_null const &) = default;
non_null & operator=(non_null const &) = default;
// also allow assignment from non-null convertible pointers
template<
typename U,
typename Enable = typename std::enable_if<
std::is_convertible<U *, T *>::value
&& !std::is_same<U *, T *>::value
>::type
> constexpr non_null & operator=(non_null<U> const & convertible) noexcept
{
// other than constexpr std::addressof,
// the rest of this should all work in c++11,
// so we'll meet c++11's restrictions on constexpr
// by using the comma operator to do the assignment
return ((raw = static_cast<U *>(convertible)), *this);
}
constexpr reference operator*() const noexcept
{return *raw;}
constexpr pointer operator->() const noexcept
{return raw;}
// I have chosen implicit conversions in this example
// but you could make them explicit if you prefer
constexpr operator reference () const noexcept
{ return *raw;}
constexpr operator pointer () const noexcept
{return raw;}
};
// you could verify with whatever type you want
static_assert(
std::is_trivially_copyable<non_null<int> >::value
&& std::is_trivially_destructible<non_null<int> >::value,
"inappropriate overhead"
);
}