BDE 4.14.0 Production release
Loading...
Searching...
No Matches
bslalg_nothrowmovableutil.h
Go to the documentation of this file.
1/// @file bslalg_nothrowmovableutil.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// bslalg_nothrowmovableutil.h -*-C++-*-
8
9#ifndef INCLUDED_BSLALG_NOTHROWMOVABLEUTIL
10#define INCLUDED_BSLALG_NOTHROWMOVABLEUTIL
11
12#include <bsls_ident.h>
13BSLS_IDENT("$Id: $")
14
15/// @defgroup bslalg_nothrowmovableutil bslalg_nothrowmovableutil
16/// @brief Provide a wrapper that asserts a noexcept move constructor.
17/// @addtogroup bsl
18/// @{
19/// @addtogroup bslalg
20/// @{
21/// @addtogroup bslalg_nothrowmovableutil
22/// @{
23///
24/// <h1> Outline </h1>
25/// * <a href="#bslalg_nothrowmovableutil-purpose"> Purpose</a>
26/// * <a href="#bslalg_nothrowmovableutil-classes"> Classes </a>
27/// * <a href="#bslalg_nothrowmovableutil-description"> Description </a>
28/// * <a href="#bslalg_nothrowmovableutil-usage"> Usage </a>
29/// * <a href="#bslalg_nothrowmovableutil-example"> Example </a>
30///
31/// # Purpose {#bslalg_nothrowmovableutil-purpose}
32/// Provide a wrapper that asserts a noexcept move constructor.
33///
34/// # Classes {#bslalg_nothrowmovableutil-classes}
35///
36/// - bslalg::NothrowMovableUtil: utilities for @ref bslalg_nothrowmovablewrapper
37///
38/// @see bslalg_nothrowmovablewrapper
39///
40/// # Description {#bslalg_nothrowmovableutil-description}
41/// This component provides a utility struct,
42/// `bslalg::NothrowMovableUtil`, for managing @ref bslalg_nothrowmovablewrapper
43/// objects. It provides a namespace for static functions `wrap` and `unwrap`
44/// with a uniform interface such that unwrapping an object that is not wrapped
45/// or wrapping an object that is already wrapped are no-ops. This utility
46/// struct also provides type traits for determining whether a type is wrapped
47/// and for deducing the type of the wrapped and unwrapped object.
48///
49/// ## Usage {#bslalg_nothrowmovableutil-usage}
50///
51///
52///
53/// ### Example {#bslalg_nothrowmovableutil-example}
54///
55///
56/// In this example, we define a class template, `CountedType<TYPE>`, a wrapper
57/// around `TYPE` that counts the number of extant `CountedType` objects. We
58/// begin by defining the static count member along with the single value
59/// member:
60/// @code
61/// template <class TYPE>
62/// class CountedType {
63/// // CLASS DATA
64/// static int s_count;
65///
66/// // DATA
67/// TYPE d_value;
68/// @endcode
69/// Because of externally-imposed requirements, the move constructor for
70/// `CountedType` must provide the strong guarantee; i.e., if the move
71/// constructor of `TYPE` throws an exception, then the moved-from `CountedType`
72/// object must be left unchanged. To support this requirement, we next define
73/// a private static function, `MoveIfNoexcept`, similar to the standard
74/// `std::move_if_noexcept`, that returns a movable reference if its argument is
75/// no-throw move constructible and a const lvalue reference otherwise:
76/// @code
77/// // PRIVATE CLASS FUNCTIONS
78/// template <class TP>
79/// static typename
80/// bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value,
81/// bslmf::MovableRef<TP>, const TP&>::type
82/// MoveIfNoexcept(TP& x);
83/// @endcode
84/// We next finish out the class definition with a constructor, copy
85/// constructor, move constructor, destructor, and member functions to retrieve
86/// the count and value:
87/// @code
88/// public:
89/// // CLASS FUNCTIONS
90///
91/// static int count() { return s_count; }
92///
93/// // CREATORS
94///
95/// /// Construct `CountedType` from the specified `val`.
96/// CountedType(const TYPE& val);
97///
98/// /// Copy construct `*this` from the specified `original` object.
99/// CountedType(const CountedType& original);
100///
101/// /// Move construct `*this` from `original`. If an exception is
102/// /// thrown, by the constructor for `TYPE` `original` is unchanged.
103/// CountedType(bslmf::MovableRef<CountedType> original);
104///
105/// /// Destroy this object.
106/// ~CountedType() { --s_count; }
107///
108/// // MANIPULATORS
109///
110/// TYPE& value() { return d_value; }
111///
112/// // ACCESSORS
113///
114/// const TYPE& value() const { return d_value; }
115/// };
116/// @endcode
117/// Next, we implement `MoveIfNoexcept`, which calls `move` on its argument,
118/// allowing it to convert back to an lvalue if the return type is an lvalue
119/// reference:
120/// @code
121/// template <class TYPE>
122/// template <class TP>
123/// inline typename
124/// bsl::conditional<bsl::is_nothrow_move_constructible<TP>::value,
125/// bslmf::MovableRef<TP>, const TP&>::type
126/// CountedType<TYPE>::MoveIfNoexcept(TP& x)
127/// {
128/// return bslmf::MovableRefUtil::move(x);
129/// }
130/// @endcode
131/// Next, we implement the value constructor and copy constructor, which simply
132/// copy their argument into the `d_value` data members and increment the count:
133/// @code
134/// template <class TYPE>
135/// CountedType<TYPE>::CountedType(const TYPE& val) : d_value(val)
136/// {
137/// ++s_count;
138/// }
139///
140/// template <class TYPE>
141/// CountedType<TYPE>::CountedType(const CountedType& original)
142/// : d_value(original.d_value)
143/// {
144/// ++s_count;
145/// }
146/// @endcode
147/// We're now ready implement the move constructor. Logically, we would simply
148/// move the value from `original` into the `d_value` member of `*this`, but an
149/// exception thrown by `TYPE`'s move constructor would leave `original` in a
150/// (valid but) unspecified state, violating the strong guarantee. Instead, we
151/// move the value only if we know that the move will succeed; otherwise, we
152/// copy it. This behavior is facilitated by the `MoveIfNoexcept` function
153/// defined above:
154/// @code
155/// template <class TYPE>
156/// CountedType<TYPE>::CountedType(bslmf::MovableRef<CountedType> original)
157/// : d_value(
158/// MoveIfNoexcept(bslmf::MovableRefUtil::access(original).d_value))
159/// {
160/// ++s_count;
161/// }
162/// @endcode
163/// Finally, we define the `s_count` member to complete the class
164/// implementation:
165/// @code
166/// template <class TYPE>
167/// int CountedType<TYPE>::s_count = 0;
168/// @endcode
169/// To test the `CountedType` class template, assume a simple client type,
170/// `SomeType` that makes it easy to detect if it was move constructed.
171/// `SomeType` holds an `int` value that is set to -1 when it is moved from, as
172/// shown here:
173/// @code
174/// class SomeType {
175/// int d_value;
176/// public:
177/// SomeType(int v = 0) : d_value(v) { } // IMPLICIT
178/// SomeType(const SomeType& original) : d_value(original.d_value) { }
179/// SomeType(bslmf::MovableRef<SomeType> original)
180/// : d_value(bslmf::MovableRefUtil::access(original).d_value)
181/// { bslmf::MovableRefUtil::access(original).d_value = -1; }
182///
183/// int value() const { return d_value; }
184/// };
185/// @endcode
186/// Notice that `SomeType` neglected to declare its move constructor as
187/// `noexcept`. This might be an oversight or it could be an old class that
188/// predates both `noexcept` and the `bsl::is_nothrow_move_constructible` trait.
189/// It is even be possible that the move constructor might throw (though, of
190/// course, it doesn't in this simplified example). Regardless, the effect is
191/// that move-constructing a `CountedType<SomeType>` will result in the move
192/// constructor actually performing a copy:
193/// @code
194/// void main()
195/// {
196/// CountedType<SomeType> obj1(1);
197/// CountedType<SomeType> obj2(bslmf::MovableRefUtil::move(obj1));
198/// assert(1 == obj1.value().value()); // Copied, not moved from
199/// assert(1 == obj2.value().value());
200/// @endcode
201/// For the purpose of this example, we can be sure that `SomeThing` will not
202/// throw on move, at least not in our application. In order to obtain the
203/// expected move optimization, we next wrap our 'SomeType in a
204/// `bslalg::NothrowMovableWrapper`:
205/// @code
206/// CountedType<bslalg::NothrowMovableWrapper<SomeType> >
207/// obj3(SomeType(3));
208/// CountedType<bslalg::NothrowMovableWrapper<SomeType> >
209/// obj4(bslmf::MovableRefUtil::move(obj3));
210/// assert(-1 == obj3.value().unwrap().value()); // moved from
211/// assert(3 == obj4.value().unwrap().value());
212/// }
213/// @endcode
214///
215/// Note that, in the last two lines of `main`, we must call `unwrap` in order
216/// to access the `SomeType` object inside of the `NothrowMovableWrapper`. This
217/// is one situation where it would be attractive to have an overloadable
218/// "operator dot" so that both `CountedThing` and `NothrowMovableWrapper` could
219/// be transparent proxy types. C++ does not have overloadable operator dot,
220/// but we can create a `CountedType` that is more intelligent about the
221/// existence of `NothrowMovableWrapper` and automatically unwraps values for
222/// the user's convenience.
223///
224/// Rather than starting from scratch, we'll build our new counted type,
225/// `CountedType2` on `CountedType`. We start be defining a single data member
226/// of type `CountedType`:
227/// @code
228/// template <class TYPE>
229/// class CountedType2 {
230/// CountedType<TYPE> d_data;
231/// @endcode
232/// Next, for convenience, we add a public data type, `ValueType` for the value
233/// stored within `CountedType2`. However, rather than defining `ValueType` as
234/// simply `TYPE`, we want to know if it is an instantiation of
235/// `NothrowMovableWrapper<TP>`. If it is, we want a type that represents the
236/// unwrapped `TP` rather than the full `TYPE`. For this type transformation,
237/// we turn to the type traits defined in `bslalg::NothrowMovableUtil`:
238/// @code
239/// public:
240/// // TYPES
241/// typedef typename
242/// bslalg::NothrowMovableUtil::UnwrappedType<TYPE>::type ValueType;
243/// @endcode
244/// Note that the `UnwrappedType` metafunction has no affect if `TYPE` is not
245/// wrapped.
246///
247/// Next, we declare (and define) the class functions, constructors, and
248/// destructor, simply forwarding to the corresponding `CountedType` function,
249/// constructor, or destructor:
250/// @code
251/// // CLASS FUNCTIONS
252/// static int count() { return CountedType<TYPE>::count(); }
253///
254/// // CREATORS
255/// CountedType2(const TYPE& val) : d_data(val) { }
256/// CountedType2(const CountedType2& original)
257/// : d_data(original.d_data) { }
258/// CountedType2(bslmf::MovableRef<CountedType2> original)
259/// : d_data(bslmf::MovableRefUtil::move(
260/// bslmf::MovableRefUtil::access(original).d_data)) { }
261/// @endcode
262/// Finally, we implement the `value()` members such that the returned values do
263/// not need to be unwrapped. As in the case of the `UnwrappedType`
264/// metafunction, the `unwrap()` function in `NothrowMovableUtil` handles both
265/// wrapped and unwrapped arguments, unwrapping the latter and returning an
266/// unmodified reference to the former:
267/// @code
268/// // MANIPULATORS
269/// ValueType& value()
270/// {
271/// return bslalg::NothrowMovableUtil::unwrap(d_data.value());
272/// // Alternatively: 'return d_data.value();'
273/// }
274///
275/// // ACCESSORS
276/// const ValueType& value() const
277/// {
278/// return bslalg::NothrowMovableUtil::unwrap(d_data.value());
279/// // Alternatively: 'return d_data.value();'
280/// }
281/// };
282/// @endcode
283/// Note the alternative code for these members: A `NothrowMovableWrapper<TP>`
284/// object is implicitly convertible to `TP&`, so if `TYPE` is a
285/// `NothrowMovableWrapper`, the simple return statement will implicitly unwrap
286/// it.
287///
288/// Using a similar example for `CountedType2` as we used for `CountedType`, we
289/// see that the usage of `CountedType2` with and without
290/// `NothrowMovableWrapper` is the same:
291/// @code
292/// void main()
293/// {
294/// CountedType2<SomeType> obj1(1);
295/// CountedType2<SomeType> obj2(bslmf::MovableRefUtil::move(obj1));
296/// assert(1 == obj1.value().value()); // Copied, not moved from
297/// assert(1 == obj2.value().value());
298///
299/// CountedType2<bslalg::NothrowMovableWrapper<SomeType> >
300/// obj3(SomeType(3));
301/// CountedType2<bslalg::NothrowMovableWrapper<SomeType> >
302/// obj4(bslmf::MovableRefUtil::move(obj3));
303/// assert(-1 == obj3.value().value()); // moved from
304/// assert(3 == obj4.value().value()); // No need to call 'unwrap'
305/// }
306/// @endcode
307/// @}
308/** @} */
309/** @} */
310
311/** @addtogroup bsl
312 * @{
313 */
314/** @addtogroup bslalg
315 * @{
316 */
317/** @addtogroup bslalg_nothrowmovableutil
318 * @{
319 */
320
321#include <bslscm_version.h>
322
324
325#include <bslmf_assert.h>
326#include <bslmf_conditional.h>
327#include <bslmf_isarray.h>
328#include <bslmf_isfunction.h>
329#include <bslmf_movableref.h>
330#include <bslmf_removecv.h>
331
332
333namespace bslalg {
334
335// FORWARD DECLARATION
336template <class TYPE, bool = bsl::is_function<TYPE>::value>
338
339 // =========================
340 // struct NothrowMovableUtil
341 // =========================
342
343/// Namesapace for `NothrowMovableWrapper` traits and utilities.
345
346 // TRAITS
347
348 /// Metafunction evaluating to `true_type` if `TYPE` is a specialization
349 /// of `NothrowMovableWrapper`; otherwise, `false_type`.
350 template <class TYPE>
351 struct IsWrapped : NothrowMovableUtil_Traits<TYPE>::IsWrapped {
352 };
353
354 /// Metafunction: If `TYPE` is a specialization of
355 /// `NothrowMovableWrapper`, then `WrappedType<TYPE>::type` is `TYPE`;
356 /// otherwise `WrappedType<TYPE>::type` is
357 /// `NothrowMovableWrapper<TYPE>`.
358 template <class TYPE>
363
364 /// Metafunction: If `TYPE` is a specialization of
365 /// `NothrowMovableWrapper`, then `Unwrapped<TYPE>::type` is
366 /// `TYPE::ValueType`; otherwise `Unwrapped<TYPE>::type` is `TYPE`.
367 template <class TYPE>
372
373 // CLASS METHODS
374
375 /// Return a reference to the object wrapped in the specified `f`
376 /// object. If `f` is not wrapped, simply return a reference to `f`. Note
377 /// that the overloads taking an lvalue argument prevent the overload
378 /// taking an rvalue argument from treating the argument as a forwarding
379 /// reference. The return type is chosen so both the value category and
380 /// constness of the parameter are preserved even in the case of const
381 /// rvalue references.
382 template <class TYPE>
383 static typename UnwrappedType<TYPE>::type& unwrap(TYPE& f);
384 template <class TYPE>
385 static typename UnwrappedType<TYPE>::type const& unwrap(TYPE const& f);
386 template <class TYPE>
389 template <class TYPE>
392
393 /// Return a wrapped copy of the specified `f` object. If `f` is
394 /// already wrapped, return a simple copy of `f` without wrapping it
395 /// again. Note that the overloads taking an lvalue argument prevent
396 /// the overload taking an rvalue argument from treating the argument as
397 /// a forwarding reference.
398 template <class TYPE>
399 static typename WrappedType<TYPE>::type wrap(TYPE& f);
400 template <class TYPE>
401 static typename WrappedType<TYPE>::type wrap(TYPE const& f);
402 template <class TYPE>
403 static typename WrappedType<TYPE>::type
405 template <class TYPE>
406 static typename WrappedType<TYPE>::type
408};
409
410} // close package namespace
411
412 // ----------------------------------------
413 // class template NothrowMovableUtil_Traits
414 // ----------------------------------------
415
416namespace bslalg {
417
418/// Component-private class -- do not use. This specialization of traits is
419/// for non-function types that are not wrapped.
420template <class TYPE>
421struct NothrowMovableUtil_Traits<TYPE, false /* is_function */> {
422
423 // Should not be instantiated on reference types or array types. Assert
424 // for 'IsReference' needs to be commented out because in C++03
425 // 'NothrowMovableUtil_Traits' may be instantiated with a 'MovableRef'
426 // while doing overload resolution for calls to 'wrap'/'unwrap'.
427 // BSLMF_ASSERT(!bslmf::MovableRefUtil::IsReference<TYPE>::value);
429
430 //TYPES
431
433 typedef TYPE UnwrappedType;
435};
436
437/// Component-private class -- do not use. This specialization of traits is
438/// for function types that are not wrapped. This specialization is NOT for
439/// function pointers or function references.
440///
441/// `UnwrappedType` is an object type, and is thus the decayed version of
442/// `TYPE`, i.e., a function pointer. Since `unwrap` always returns a
443/// reference, this decay means that, `unwrap(f)` will not compile if `f` is
444/// a function or reference to function. However `UnwrappedType pf = f;`
445/// will work whether `f` is a function or not.
446template <class TYPE>
447struct NothrowMovableUtil_Traits<TYPE, true /* is_function */> {
448
449 // TYPES
451 typedef TYPE *UnwrappedType;
453};
454
455/// Component-private class -- do not use. This specialization is for
456/// wrapped types.
457template <class TYPE>
465
466} // close package namespace
467
468// ============================================================================
469// TEMPLATE AND INLINE IMPLEMENTATIONS
470// ============================================================================
471
472 // -----------------------------------------
473 // struct template NothrowMovableUtil
474 // -----------------------------------------
475
476// PUBLIC CLASS METHODS
477
478template <class TYPE>
479inline
482{
483 return f;
484}
485
486template <class TYPE>
487inline
490{
491 return f;
492}
493
494template <class TYPE>
495inline
504
505template <class TYPE>
506inline
515
516template <class TYPE>
517inline
520{
521 return f;
522}
523
524template <class TYPE>
525inline
528{
529 return f;
530}
531
532template <class TYPE>
533inline
539
540template <class TYPE>
541inline
545{
546 return
547 typename WrappedType<typename bslmf::MovableRefUtil::RemoveReference<
548 TYPE>::type>::type(bslmf::MovableRefUtil::move(f));
549}
550
551
552
553#endif // ! defined(INCLUDED_BSLALG_NOTHROWMOVABLEUTIL)
554
555// ----------------------------------------------------------------------------
556// Copyright 2020 Bloomberg Finance L.P.
557//
558// Licensed under the Apache License, Version 2.0 (the "License");
559// you may not use this file except in compliance with the License.
560// You may obtain a copy of the License at
561//
562// http://www.apache.org/licenses/LICENSE-2.0
563//
564// Unless required by applicable law or agreed to in writing, software
565// distributed under the License is distributed on an "AS IS" BASIS,
566// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
567// See the License for the specific language governing permissions and
568// limitations under the License.
569// ----------------------------- END-OF-FILE ----------------------------------
570
571/** @} */
572/** @} */
573/** @} */
Definition bslalg_nothrowmovablewrapper.h:269
Definition bslmf_movableref.h:751
#define BSLMF_MOVABLEREF_DEDUCE(...)
Definition bslmf_movableref.h:690
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition bdlc_flathashmap.h:1805
Definition bslmf_integralconstant.h:244
Definition bslmf_isarray.h:168
Definition bslalg_nothrowmovableutil.h:351
Definition bslalg_nothrowmovableutil.h:368
NothrowMovableUtil_Traits< TYPE >::UnwrappedType type
Definition bslalg_nothrowmovableutil.h:370
Definition bslalg_nothrowmovableutil.h:359
NothrowMovableUtil_Traits< TYPE >::WrappedType type
Definition bslalg_nothrowmovableutil.h:361
NothrowMovableWrapper< TYPE > WrappedType
Definition bslalg_nothrowmovableutil.h:463
bsl::true_type IsWrapped
Definition bslalg_nothrowmovableutil.h:461
TYPE UnwrappedType
Definition bslalg_nothrowmovableutil.h:462
TYPE UnwrappedType
Definition bslalg_nothrowmovableutil.h:433
bsl::false_type IsWrapped
Definition bslalg_nothrowmovableutil.h:432
BSLMF_ASSERT(!bsl::is_array< TYPE >::value)
NothrowMovableWrapper< TYPE > WrappedType
Definition bslalg_nothrowmovableutil.h:434
TYPE * UnwrappedType
Definition bslalg_nothrowmovableutil.h:451
bsl::false_type IsWrapped
Definition bslalg_nothrowmovableutil.h:450
NothrowMovableWrapper< TYPE * > WrappedType
Definition bslalg_nothrowmovableutil.h:452
Definition bslalg_nothrowmovableutil.h:337
Namesapace for NothrowMovableWrapper traits and utilities.
Definition bslalg_nothrowmovableutil.h:344
static UnwrappedType< TYPE >::type const & unwrap(TYPE const &f)
static bslmf::MovableRef< typename UnwrappedType< TYPE >::type > unwrap(BSLMF_MOVABLEREF_DEDUCE(TYPE) f)
static WrappedType< TYPE >::type wrap(TYPE &f)
static WrappedType< TYPE >::type wrap(TYPE const &f)
static UnwrappedType< TYPE >::type & unwrap(TYPE &f)
static WrappedType< TYPE >::type wrap(BSLMF_MOVABLEREF_DEDUCE(TYPE) f)
static WrappedType< TYPE >::type wrap(BSLMF_MOVABLEREF_DEDUCE(const TYPE) f)
static bslmf::MovableRef< const typename UnwrappedType< TYPE >::type > unwrap(BSLMF_MOVABLEREF_DEDUCE(const TYPE) f)
Definition bslmf_movableref.h:825
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1060
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1032