Skip to content

Commit

Permalink
libcore: Added new AS_IS method expectedAs<>()
Browse files Browse the repository at this point in the history
Used like as<>() but throws an exception if the cast is illegal.
  • Loading branch information
skyjake committed Oct 16, 2015
1 parent 7b09dee commit 7f179c0
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 2 deletions.
7 changes: 5 additions & 2 deletions doomsday/sdk/libcore/include/de/error.h
Expand Up @@ -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</small>
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_ERROR_H
Expand Down Expand Up @@ -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
Expand All @@ -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
21 changes: 21 additions & 0 deletions doomsday/sdk/libcore/include/de/libcore.h
Expand Up @@ -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 <typename T_> \
bool is() const { return dynamic_cast<T_ const *>(this) != 0; } \
Expand All @@ -283,6 +294,16 @@
T_ *maybeAs() { return dynamic_cast<T_ *>(this); } \
template <typename T_> \
T_ const *maybeAs() const { return dynamic_cast<T_ const *>(this); } \
template <typename T_> \
T_ &expectedAs() { \
if(auto *t = maybeAs<T_>()) return *t; \
throw CastError(QString("Cannot cast %1 to %2").arg(DENG2_TYPE_NAME(this)).arg(DENG2_TYPE_NAME(T_))); \
} \
template <typename T_> \
T_ const &expectedAs() const { \
if(auto const *t = maybeAs<T_>()) 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
Expand Down

0 comments on commit 7f179c0

Please sign in to comment.