diff --git a/doomsday/sdk/libcore/include/de/error.h b/doomsday/sdk/libcore/include/de/error.h index f202bcfbce..87bebe11fc 100644 --- a/doomsday/sdk/libcore/include/de/error.h +++ b/doomsday/sdk/libcore/include/de/error.h @@ -14,7 +14,7 @@ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy of * the GNU Lesser General Public License along with this program; if not, see: - * http://www.gnu.org/licenses + * http://www.gnu.org/licenses */ #ifndef LIBDENG2_ERROR_H @@ -54,7 +54,7 @@ class DENG2_PUBLIC Error : public std::runtime_error }; } // namespace de - + /** * Macro for defining an exception class that belongs to a parent group of * exceptions. This should be used so that whoever uses the class @@ -77,4 +77,7 @@ class DENG2_PUBLIC Error : public std::runtime_error */ #define DENG2_ERROR(Name) DENG2_SUB_ERROR(de::Error, Name) +/// Thrown from the expectedAs() method if a cast cannot be made as expected. +DENG2_ERROR(CastError); + #endif // LIBDENG2_ERROR_H diff --git a/doomsday/sdk/libcore/include/de/libcore.h b/doomsday/sdk/libcore/include/de/libcore.h index 8e06174a89..56ea71353e 100644 --- a/doomsday/sdk/libcore/include/de/libcore.h +++ b/doomsday/sdk/libcore/include/de/libcore.h @@ -266,6 +266,17 @@ #define DENG2_NO_COPY(ClassName) \ private: ClassName(ClassName const &); +/** + * Macro for declaring methods for convenient casting: + * + * - `is` checks if the object can be casted. + * - `as` performs the cast as efficiently as possible (just a `static_cast`). + * Use this when the cast is always known to be legal. + * - `maybeAs` does a `dynamic_cast` (which has slower performance). Failure + * to cast simply results in nullptr. + * - `expectedAs` does a `dynamic_cast` and throws an exception if the cast fails. + * Slowest performance, but is the safest. + */ #define DENG2_AS_IS_METHODS() \ template \ bool is() const { return dynamic_cast(this) != 0; } \ @@ -283,6 +294,16 @@ T_ *maybeAs() { return dynamic_cast(this); } \ template \ T_ const *maybeAs() const { return dynamic_cast(this); } \ + template \ + T_ &expectedAs() { \ + if(auto *t = maybeAs()) return *t; \ + throw CastError(QString("Cannot cast %1 to %2").arg(DENG2_TYPE_NAME(this)).arg(DENG2_TYPE_NAME(T_))); \ + } \ + template \ + T_ const &expectedAs() const { \ + if(auto const *t = maybeAs()) return *t; \ + throw CastError(QString("Cannot cast %1 to %2").arg(DENG2_TYPE_NAME(this)).arg(DENG2_TYPE_NAME(T_))); \ + } /** * Macro for starting the definition of a private implementation struct. The