BDE 4.14.0 Production release
|
Functions | |
template<class TYPE > | |
bslalg::NothrowMovableUtil::UnwrappedType< TYPE >::type & | bslalg::NothrowMovableUtil::unwrap (TYPE &f) |
template<class TYPE > | |
bslalg::NothrowMovableUtil::UnwrappedType< TYPE >::type const & | bslalg::NothrowMovableUtil::unwrap (TYPE const &f) |
template<class TYPE > | |
bslmf::MovableRef< const typename bslalg::NothrowMovableUtil::UnwrappedType< TYPE >::type > | bslalg::NothrowMovableUtil::unwrap (BSLMF_MOVABLEREF_DEDUCE(const TYPE) f) |
template<class TYPE > | |
bslalg::NothrowMovableUtil::WrappedType< TYPE >::type | bslalg::NothrowMovableUtil::wrap (TYPE &f) |
template<class TYPE > | |
bslalg::NothrowMovableUtil::WrappedType< TYPE >::type | bslalg::NothrowMovableUtil::wrap (const TYPE &f) |
template<class TYPE > | |
bslalg::NothrowMovableUtil::WrappedType< TYPE >::type | bslalg::NothrowMovableUtil::wrap (BSLMF_MOVABLEREF_DEDUCE(const TYPE) f) |
Provide a wrapper that asserts a noexcept move constructor.
This component provides a utility struct, bslalg::NothrowMovableUtil
, for managing bslalg_nothrowmovablewrapper objects. It provides a namespace for static functions wrap
and unwrap
with a uniform interface such that unwrapping an object that is not wrapped or wrapping an object that is already wrapped are no-ops. This utility struct also provides type traits for determining whether a type is wrapped and for deducing the type of the wrapped and unwrapped object.
In this example, we define a class template, CountedType<TYPE>
, a wrapper around TYPE
that counts the number of extant CountedType
objects. We begin by defining the static count member along with the single value member:
Because of externally-imposed requirements, the move constructor for CountedType
must provide the strong guarantee; i.e., if the move constructor of TYPE
throws an exception, then the moved-from CountedType
object must be left unchanged. To support this requirement, we next define a private static function, MoveIfNoexcept
, similar to the standard std::move_if_noexcept
, that returns a movable reference if its argument is no-throw move constructible and a const lvalue reference otherwise:
We next finish out the class definition with a constructor, copy constructor, move constructor, destructor, and member functions to retrieve the count and value:
Next, we implement MoveIfNoexcept
, which calls move
on its argument, allowing it to convert back to an lvalue if the return type is an lvalue reference:
Next, we implement the value constructor and copy constructor, which simply copy their argument into the d_value
data members and increment the count:
We're now ready implement the move constructor. Logically, we would simply move the value from original
into the d_value
member of *this
, but an exception thrown by TYPE
's move constructor would leave original
in a (valid but) unspecified state, violating the strong guarantee. Instead, we move the value only if we know that the move will succeed; otherwise, we copy it. This behavior is facilitated by the MoveIfNoexcept
function defined above:
Finally, we define the s_count
member to complete the class implementation:
To test the CountedType
class template, assume a simple client type, SomeType
that makes it easy to detect if it was move constructed. SomeType
holds an int
value that is set to -1 when it is moved from, as shown here:
Notice that SomeType
neglected to declare its move constructor as noexcept
. This might be an oversight or it could be an old class that predates both noexcept
and the bsl::is_nothrow_move_constructible
trait. It is even be possible that the move constructor might throw (though, of course, it doesn't in this simplified example). Regardless, the effect is that move-constructing a CountedType<SomeType>
will result in the move constructor actually performing a copy:
For the purpose of this example, we can be sure that SomeThing
will not throw on move, at least not in our application. In order to obtain the expected move optimization, we next wrap our 'SomeType in a bslalg::NothrowMovableWrapper
:
Note that, in the last two lines of main
, we must call unwrap
in order to access the SomeType
object inside of the NothrowMovableWrapper
. This is one situation where it would be attractive to have an overloadable "operator dot" so that both CountedThing
and NothrowMovableWrapper
could be transparent proxy types. C++ does not have overloadable operator dot, but we can create a CountedType
that is more intelligent about the existence of NothrowMovableWrapper
and automatically unwraps values for the user's convenience.
Rather than starting from scratch, we'll build our new counted type, CountedType2
on CountedType
. We start be defining a single data member of type CountedType
:
Next, for convenience, we add a public data type, ValueType
for the value stored within CountedType2
. However, rather than defining ValueType
as simply TYPE
, we want to know if it is an instantiation of NothrowMovableWrapper<TP>
. If it is, we want a type that represents the unwrapped TP
rather than the full TYPE
. For this type transformation, we turn to the type traits defined in bslalg::NothrowMovableUtil
:
Note that the UnwrappedType
metafunction has no affect if TYPE
is not wrapped.
Next, we declare (and define) the class functions, constructors, and destructor, simply forwarding to the corresponding CountedType
function, constructor, or destructor:
Finally, we implement the value()
members such that the returned values do not need to be unwrapped. As in the case of the UnwrappedType
metafunction, the unwrap()
function in NothrowMovableUtil
handles both wrapped and unwrapped arguments, unwrapping the latter and returning an unmodified reference to the former:
Note the alternative code for these members: A NothrowMovableWrapper<TP>
object is implicitly convertible to TP&
, so if TYPE
is a NothrowMovableWrapper
, the simple return statement will implicitly unwrap it.
Using a similar example for CountedType2
as we used for CountedType
, we see that the usage of CountedType2
with and without NothrowMovableWrapper
is the same:
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |
|
inline |