Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using std::error_code with non-integer values

I'm writing a library and want to return error codes whenever an error is returned by a remote system. The problem is that these are identified by strings, eg, "0A01" and also contain a message, and error code requires an integer as value.

What is the best way to implement an error code, with all the functionality that std::error_code provides but that uses strings as the value? How do I add an external error string to the std::error_code or std::error_category?

like image 263
ruipacheco Avatar asked Oct 18 '22 12:10

ruipacheco


1 Answers

As mentioned in the comments, you must know the error codes, which could be received from the remote server. The std::string which you receive from a remote server contains 2 parts as you said,

The problem is that these are identified by strings, eg, "0A01" and also contain a message, and error code requires an integer as value.

As you haven't shared the format of the error message, I am not adding the code for spiting it, split your string into 2 parts,

  1. Error Code
  2. Error Message

Now you can convert Error Code of type std::string to int by using std::stoi(error_code), So lets say

int error_code_int = std::stoi(string_to_hexadecimal(error_code));

And for std::error_category which serves as base class for our custom error messages, do this,

std::string message_received = "This is the message which received from remote server.";

struct OurCustomErrCategory : std::error_category
{
  const char* name() const noexcept override;
  std::string message(int ev) const override;
};

const char* OurCustomErrCategory::name() const noexcept
{
  return "Error Category Name";
}

std::string OurCustomErrCategory::message(int error_code_int) const
{
    switch (error_code_int)
    {
    case 1:
        return message_received;

    default:
        return "(unrecognized error)";
  }
}

const OurCustomErrCategory ourCustomErrCategoryObject;

std::error_code make_error_code(int e)
{
  return {e, ourCustomErrCategoryObject};
}

int main()
{
    int error_code_int = std::stoi(string_to_hexadecimal(error_code));  // error_code = 0A01
    ourCustomErrCategoryObject.message(error_code_int);
    std::error_code ec(error_code_int , ourCustomErrCategoryObject);
    assert(ec);

    std::cout << ec << std::endl;
    std::cout << ec.message() << std::endl;
}

The output for above working example is

Error Category Name : 0A01
This is the message which received from remote server.

You can use function string_to_hexadecimal() from this post.

I hope that now you can modify the above code according to your needs.

Edit 1:

As you said that:

This assumes the dynamic message is a global value. How do I pass it to an std::error_category object?

You can see that both std::error_code::assign and constructor std::error_code::error_code are taking parameters of int for error code number and error_category. So It is obvious that std::error_code can't take the dynamic message.

But wait, I said std::error_code are taking error_category as an argument in constructor, so is there any way, we can assign the dynamic message there ?

std::error_category states that:

std::error_category serves as the base class for specific error category types.

So it means that the struct we derived from std::error_category at the following line

struct OurCustomErrCategory : std::error_category

can have a data member and we can assign it via member function, so our struct will become like that,

struct OurCustomErrCategory : std::error_category
{
    std::string message_received;
    OurCustomErrCategory(std::string m) : message_received(m) {}

    const char* name() const noexcept override;
    std::string message(int ev) const override;
};

and you can assign it like that wherever you want,

const OurCustomErrCategory ourCustomErrCategoryObject("This is the message which received from remote server.");
like image 185
Sahib Yar Avatar answered Nov 15 '22 06:11

Sahib Yar