Posts Tagged ‘convenience’

Displaying Enum-Names instead of Values in Errors

June 4th, 2009 1 comment

The usual lazy developer likes to print out plain error messages, which contain pure numbers and don’t mean anything. The most prominent example is Windows itself, back in the old days.

Some time ago I was once again faced with the decision how to handle errors in our plug-able class design. While trying to find a good solution I remembered an old blog post – Qt is able to create a mapping from enum integer values to their respective names. So I fiddled around a bit and came up with a pretty neat solution, which requires virtually no extra code to gain a little more meaningful error messages than plain integer values.

Here is what I came up with:

You need to sub-class an error base class, insert your error enumeration, and tell Qt that you need the value-to-name mapping for this enum. All the extras come with the base class.
If you don’t like the rest of the class, you might just want to check out BaseError::identifierToName(). That’s where the magic is happening.

A usage example:

 // --- header file ---
 class HorseError : public BaseError
     enum x { DOES_NOT_WANT, IS_INJURED };
 class Horse
     HorseError error;
     void ride();
 // --- source file ---
 void Horse::ride()
     error.activate(HorseError::DOES_NOT_WANT, "cannot happen anyways");
 // --- using ---
 Horse mybeautifulhorse;
 // operator() returns a bool
 if (mybeautifulhorse.error()) {
    // operator QString makes the error readable
    qDebug() < < mybeautifulhorse.error;

The Header File – BaseError.hpp

class BaseError : private QObject                                                                                                         
    virtual ~BaseError();
    /** @returns whether the error is active */
    bool active() const;                       
    /** @returns the identifier (an enum) */   
    int identifier() const;                    
    /** @returns the name of the identifier enum e.g. "MyErrorClass::MyReturnValue" */
    QString name() const;                                                             
    /** @returns the description given by activate's second parameter */              
    const QString& description() const;                                               
    /** throw the error */
    void activate(int identifier, const QString& description = QString());
    /** clear the state / remove the error */                             
    void deactivate();                                                    
    /** alias for active() */
    bool operator()() const; 
    /** @returns 'name() "description()"' e.g.
     * 'MyErrorClass::MyReturnValue "something meaningful"'
    operator QString() const;                              
    /** emitted when the error has been activated */
    void activated();                               
     * Default implementation generates a string using the
     * "DerivedErrorClassName::EnumeratorValueName"       
     * @note                                              
     * reimplement this functions to apply an own         
     * identifier-to-error-name-mapping                   
    virtual QString identifierToName(int identifier) const;
    bool m_active;
    int m_identifier;
    QString m_description;

The Source File – BaseError.cpp

#include "BaseError.hpp"
#include <qmetaenum>
BaseError::BaseError() : QObject(), m_active(false)
bool BaseError::operator()() const
    return m_active;              
BaseError::operator QString() const
    return QString("%1 \"%2\"").arg(name()).arg(description());
int BaseError::identifier() const
    return m_identifier;         
QString BaseError::name() const
    return identifierToName(m_identifier);
const QString& BaseError::description() const
    return m_description;
void BaseError::activate(int identifier, const QString& description)
    m_identifier = identifier;
    m_description = description;
    m_active = true;
    emit activated();
void BaseError::deactivate()
    m_active = false;
QString BaseError::identifierToName(int identifier) const
    QStringList ret;
    const QMetaObject* meta = metaObject();
    for (int i=0; i < meta->enumeratorCount(); ++i) {
        QMetaEnum enumerator = meta->enumerator(i);
        ret < < QString("%1::%2").arg(enumerator.scope()).arg(enumerator.key(identifier));
    return ret.join(", ");

Categories: c/c++, qt, software Tags: , , , , ,