My goal is to make a consistent and easy way to determine how a function fails/succeeds. I'm looking for code review of my Status class for any bad practices, code that isn't thread-safe and general improvements and changes.For logging and debugging I always needed to know how a function failed and print this out as readable text. The solution I usually employed was using enumerations - enum ERROR_CODE {..}; - which is fine except they cannot be expanded/overridden - I'm making an API so enums don't allow the user to expand/add custom error codes. They also don't print out nicely to describe what error actually occurred - they just print out as numbers. So I made a status class.Main features:Allows creation of error/states wherever & whenever (runtime, compile time):static const Status S_SUCCESS         = CStatus::registerState(Success);static const Status S_EMPTY_CONTAINER = CStatus::registerState(Empty rectangle vectors);General usage:Status unionRectangles(const vector<Rect>& left, vector<Rect>& right){  if (left.size() <= 0 || right.size() <= 0)     return S_EMPTY_CONTAINER;  ...  return S_SUCCESS;}Print out descriptive errors without requiring conversion:vector<Rect> v1, v2;Status myStatus = unionRects(v1, v2)cout << myStatus << end; // Empty rectangle vectorsEasily and efficiently compare objects without conversion:if (myStatus == S_SUCCESS) // for eg; resolves to if (1 == 9), ie, not string comparison    // do somethingEasy to inline check error:if (!unionRects(v1, v2))    // do somethingFull implementation:#ifndef STATUS_H#define STATUS_H#include <iostream>#include <hash_map>typedef int STATE;typedef std::hash_map<STATE, tstring>::iterator StateIterator;typedef class CStatus;typedef const CStatus Status;#ifndef S_SUCCESS#define S_SUCCESS CStatus::CS_SUCCESS#endif // S_SUCCESS#ifndef S_UNDEFINED_ERROR#define S_UNDEFINED_ERROR CStatus::CS_UNDEFINED_ERROR#endif // S_SUCCESSclass CStatus{public:    // Static Properties//    static Status CS_SUCCESS;    static Status CS_UNDEFINED_ERROR;    // Static Functions //    static Status registerState(const tstring &stateMsg)    {        // Post:         int nextStateTmp = nextState + 1;        std::pair<StateIterator, BOOL> res = states.emplace(std::make_pair(nextStateTmp, stateMsg));        // if state has been inserted        if (res.second)            return Status(++nextState);        // return existing state id        return Status(res.first->first);    }    // Properties //    const STATE state;    // Functions //    CStatus(const STATE &state)  : state(state) {}    virtual ~CStatus() {}    const tstring& toString() const     {        return (states.find(state) == states.end()) ? states[state] : _T(Undefined);    }    operator tstring() const    {        return toString();    }    operator int() const    {        return state;    }    bool operator==(const CStatus& obj) const    {        return state == obj.state;    }    bool operator!=(const CStatus& obj) const    {        return state != obj.state;    }    bool operator!() const    {        return *this != S_SUCCESS;    }    std::ostream& operator <<(std::ostream &stream, const CStatus& obj)    {        return stream << obj.toString().c_str();    }    friend std::ostream& operator<<(std::ostream& stream, const CStatus& obj);private:    static std::hash_map<STATE, tstring> states;    static STATE nextState;protected:};//static Status S_SUCCESS         = CStatus::registerState(_T(Success));//static Status S_UNDEFINED_ERROR = CStatus::registerState(_T(Undefined Error));#endif // STATUS_H
Function outcome: consistent approach and easy logging
c++;error handling;api;logging