    #include <iostream>
        #define ERROR_VALUES ERROR_VALUE(NO_ERROR, 0, "Everything is fine")\
    ERROR_VALUE(FILE_NOT_FOUND, 1, "File is not found")\
    ERROR_VALUE(LABEL_UNINITIALISED, 2, "A component tried to the label before it was initialised")\
    ERROR_VALUE(UKNOWN_ERROR, -1, "Uh oh")
    
    enum class Error
    {
    #define ERROR_VALUE(NAME,VALUE,DESCR) NAME=VALUE,
        ERROR_VALUES
    #undef ERROR_VALUE
    };
    
    inline std::ostream& operator<<(std::ostream& os, Error err)
    {
    	int errVal = static_cast<int>(err);
        switch (err)
        {
    #ifndef PRODUCTION_BUILD // Don't print out names in production builds
    #define ERROR_VALUE(NAME,VALUE,DESCR) case Error::NAME: return os << "[" #VALUE  "]" #NAME <<"; " << DESCR;
        ERROR_VALUES
    #undef ERROR_VALUE
    #endif
        default:
            return os <<errVal;
        }
    }
    
    int main() {
        std::cout << "Error: " << Error::NO_ERROR << std::endl;
        std::cout << "Error: " << Error::FILE_NOT_FOUND << std::endl;
        std::cout << "Error: " << Error::LABEL_UNINITIALISED << std::endl;
        std::cout << "Error: " << Error::UKNOWN_ERROR << std::endl;
    	return 0;
    }