From: Wolfgang Bangerth Date: Tue, 3 Apr 2018 17:14:54 +0000 (-0600) Subject: Introduce dynamic_unique_cast. X-Git-Tag: v9.0.0-rc1~224^2~2 X-Git-Url: https://gitweb.dealii.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbf76121c7c775867369198a30c5a17771000707;p=dealii.git Introduce dynamic_unique_cast. --- diff --git a/include/deal.II/base/std_cxx11/unique_ptr.h b/include/deal.II/base/std_cxx11/unique_ptr.h index d99ad5cc68..0182927a3e 100644 --- a/include/deal.II/base/std_cxx11/unique_ptr.h +++ b/include/deal.II/base/std_cxx11/unique_ptr.h @@ -33,4 +33,71 @@ DEAL_II_NAMESPACE_OPEN namespace std_cxx1x = std_cxx11; DEAL_II_NAMESPACE_CLOSE + +DEAL_II_NAMESPACE_OPEN + +/** + * Convert an object of type `std::unique_ptr` to an object of + * type `std::unique_ptr`, where it is assumed that we can cast + * the pointer to `From` to a pointer to `To` using a `dynamic_cast` + * -- in other words, we assume that `From` and `To` are connected + * through a class hierarchy, and that the object pointed to is in + * fact of a type that contains both a `From` and a `To`. An example + * is if either `To` is derived from `From` or the other way around. + * + * The function throws an exception of type `std::bad_cast` if the + * `dynamic_cast` does not succeed. This is the same exception you + * would get if a regular `dynamic_cast` between object types (but not + * pointer types) does not succeed. + * + * An example of how this function works is as follows: + * @code + * class B { ... }; // A base class. Assume that it has virtual + * // functions so that dynamic_cast can work. + * class D : public B { ... }; // A derived class + * + * + * std::unique_ptr create_object (...) {...} // A factory function + * + * void foo (...) + * { + * std::unique_ptr b = create_object (...); + * + * // Assume that we know for some reason that the object above must + * // have created a D object but returned it as a std::unique_ptr. + * // In order to access the D functionality, we need to cast the + * // pointer. Use the equivalent to dynamic_cast: + * std::unique_ptr d = dynamic_unique_cast(std::move(b)); + * + * // If the object really was a D, then 'd' now points to it. Note + * // also that in accordance with the semantics of std::unique_ptr, + * // it was necessary to std::move the 'b' object, and indeed 'b' + * // now no longer points to anything -- ownership has been + * // transferred to 'd'! + * @endcode + * + * @note This function does not try to convert the `Deleter` objects stored + * by `std::unique_ptr` objects. The function therefore only works if the + * deleter objects are at their defaults, i.e., if they are of type + * `std::default_delete` and `std::default_delete`. + */ +template +std::unique_ptr +dynamic_unique_cast (std::unique_ptr &&p) +{ + // Let's see if we can cast from 'From' to 'To'. If so, do the cast, + // and then release the pointer from the old + // owner + if (To *cast = dynamic_cast(p.get())) + { + std::unique_ptr result(cast); + p.release(); + return result; + } + else + throw std::bad_cast(); +} + +DEAL_II_NAMESPACE_CLOSE + #endif