BDE 4.39.x 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.
344///
345/// See @ref bslalg_nothrowmovableutil
347
348 // TRAITS
349
350 /// Metafunction evaluating to `true_type` if `TYPE` is a specialization
351 /// of `NothrowMovableWrapper`; otherwise, `false_type`.
352 template <class TYPE>
353 struct IsWrapped : NothrowMovableUtil_Traits<TYPE>::IsWrapped {
354 };
355
356 /// Metafunction: If `TYPE` is a specialization of
357 /// `NothrowMovableWrapper`, then `WrappedType<TYPE>::type` is `TYPE`;
358 /// otherwise `WrappedType<TYPE>::type` is
359 /// `NothrowMovableWrapper<TYPE>`.
360 ///
361 /// See @ref bslalg_nothrowmovableutil
362 template <class TYPE>
367
368 /// Metafunction: If `TYPE` is a specialization of
369 /// `NothrowMovableWrapper`, then `Unwrapped<TYPE>::type` is
370 /// `TYPE::ValueType`; otherwise `Unwrapped<TYPE>::type` is `TYPE`.
371 ///
372 /// See @ref bslalg_nothrowmovableutil
373 template <class TYPE>
378
379 // CLASS METHODS
380
381 /// Return a reference to the object wrapped in the specified `f`
382 /// object. If `f` is not wrapped, simply return a reference to `f`.
383 ///
384 /// \note Note that the overloads taking an lvalue argument prevent the overload
385 /// taking an rvalue argument from treating the argument as a forwarding
386 /// reference. The return type is chosen so both the value category and
387 /// constness of the parameter are preserved even in the case of const
388 /// rvalue references.
389 template <class TYPE>
390 static typename UnwrappedType<TYPE>::type& unwrap(TYPE& f);
391 template <class TYPE>
392 static typename UnwrappedType<TYPE>::type const& unwrap(TYPE const& f);
393 template <class TYPE>
396 template <class TYPE>
399
400 /// Return a wrapped copy of the specified `f` object. If `f` is
401 /// already wrapped, return a simple copy of `f` without wrapping it again.
402 ///
403 /// \note Note that the overloads taking an lvalue argument prevent
404 /// the overload taking an rvalue argument from treating the argument as
405 /// a forwarding reference.
406 template <class TYPE>
407 static typename WrappedType<TYPE>::type wrap(TYPE& f);
408 template <class TYPE>
409 static typename WrappedType<TYPE>::type wrap(TYPE const& f);
410 template <class TYPE>
411 static typename WrappedType<TYPE>::type
413 template <class TYPE>
414 static typename WrappedType<TYPE>::type
416};
417
418} // close package namespace
419
420 // ----------------------------------------
421 // class template NothrowMovableUtil_Traits
422 // ----------------------------------------
423
424namespace bslalg {
425
426/// Component-private class -- do not use. This specialization of traits is
427/// for non-function types that are not wrapped.
428template <class TYPE>
429struct NothrowMovableUtil_Traits<TYPE, false /* is_function */> {
430
431 // Should not be instantiated on reference types or array types. Assert
432 // for 'IsReference' needs to be commented out because in C++03
433 // 'NothrowMovableUtil_Traits' may be instantiated with a 'MovableRef'
434 // while doing overload resolution for calls to 'wrap'/'unwrap'.
435 // BSLMF_ASSERT(!bslmf::MovableRefUtil::IsReference<TYPE>::value);
437
438 //TYPES
439
441 typedef TYPE UnwrappedType;
443};
444
445/// Component-private class -- do not use. This specialization of traits is
446/// for function types that are not wrapped. This specialization is NOT for
447/// function pointers or function references.
448///
449/// `UnwrappedType` is an object type, and is thus the decayed version of
450/// `TYPE`, i.e., a function pointer. Since `unwrap` always returns a
451/// reference, this decay means that, `unwrap(f)` will not compile if `f` is
452/// a function or reference to function. However `UnwrappedType pf = f;`
453/// will work whether `f` is a function or not.
454template <class TYPE>
455struct NothrowMovableUtil_Traits<TYPE, true /* is_function */> {
456
457 // TYPES
459 typedef TYPE *UnwrappedType;
461};
462
463/// Component-private class -- do not use. This specialization is for
464/// wrapped types.
465template <class TYPE>
473
474} // close package namespace
475
476// ============================================================================
477// TEMPLATE AND INLINE IMPLEMENTATIONS
478// ============================================================================
479
480 // -----------------------------------------
481 // struct template NothrowMovableUtil
482 // -----------------------------------------
483
484// PUBLIC CLASS METHODS
485
486template <class TYPE>
487inline
490{
491 return f;
492}
493
494template <class TYPE>
495inline
498{
499 return f;
500}
501
502template <class TYPE>
503inline
512
513template <class TYPE>
514inline
523
524template <class TYPE>
525inline
528{
529 return f;
530}
531
532template <class TYPE>
533inline
536{
537 return f;
538}
539
540template <class TYPE>
541inline
547
548template <class TYPE>
549inline
553{
554 return
555 typename WrappedType<typename bslmf::MovableRefUtil::RemoveReference<
556 TYPE>::type>::type(bslmf::MovableRefUtil::move(f));
557}
558
559
560
561#endif // ! defined(INCLUDED_BSLALG_NOTHROWMOVABLEUTIL)
562
563// ----------------------------------------------------------------------------
564// Copyright 2020 Bloomberg Finance L.P.
565//
566// Licensed under the Apache License, Version 2.0 (the "License");
567// you may not use this file except in compliance with the License.
568// You may obtain a copy of the License at
569//
570// http://www.apache.org/licenses/LICENSE-2.0
571//
572// Unless required by applicable law or agreed to in writing, software
573// distributed under the License is distributed on an "AS IS" BASIS,
574// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
575// See the License for the specific language governing permissions and
576// limitations under the License.
577// ----------------------------- END-OF-FILE ----------------------------------
578
579/** @} */
580/** @} */
581/** @} */
Definition bslalg_nothrowmovablewrapper.h:269
Definition bslmf_movableref.h:752
#define BSLMF_MOVABLEREF_DEDUCE(...)
Definition bslmf_movableref.h:691
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition bdlc_flathashmap.h:2218
Definition bslmf_integralconstant.h:261
Definition bslmf_isarray.h:168
Definition bslalg_nothrowmovableutil.h:353
Definition bslalg_nothrowmovableutil.h:374
NothrowMovableUtil_Traits< TYPE >::UnwrappedType type
Definition bslalg_nothrowmovableutil.h:376
Definition bslalg_nothrowmovableutil.h:363
NothrowMovableUtil_Traits< TYPE >::WrappedType type
Definition bslalg_nothrowmovableutil.h:365
NothrowMovableWrapper< TYPE > WrappedType
Definition bslalg_nothrowmovableutil.h:471
bsl::true_type IsWrapped
Definition bslalg_nothrowmovableutil.h:469
TYPE UnwrappedType
Definition bslalg_nothrowmovableutil.h:470
TYPE UnwrappedType
Definition bslalg_nothrowmovableutil.h:441
bsl::false_type IsWrapped
Definition bslalg_nothrowmovableutil.h:440
BSLMF_ASSERT(!bsl::is_array< TYPE >::value)
NothrowMovableWrapper< TYPE > WrappedType
Definition bslalg_nothrowmovableutil.h:442
TYPE * UnwrappedType
Definition bslalg_nothrowmovableutil.h:459
bsl::false_type IsWrapped
Definition bslalg_nothrowmovableutil.h:458
NothrowMovableWrapper< TYPE * > WrappedType
Definition bslalg_nothrowmovableutil.h:460
Definition bslalg_nothrowmovableutil.h:337
Definition bslalg_nothrowmovableutil.h:346
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:829
static MovableRef< t_TYPE > move(t_TYPE &reference) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1067
static t_TYPE & access(t_TYPE &ref) BSLS_KEYWORD_NOEXCEPT
Definition bslmf_movableref.h:1039