Как написать структуру ошибки, которая может содержать различные строго типизированные перечисления в качестве кода ошибки? - PullRequest
0 голосов
/ 25 апреля 2018

Я хочу написать простую структуру ошибок, которая содержит некоторый код ошибки и std::string в качестве сообщения.Код ошибки может быть простым int или любым типом строго типизированного перечисления, например:

enum class NetworkErrorCode {
OK = 0,
CONNECTION_FAILURE,
EMPTY_RESPONSE,
HOST_RESOLUTION_FAILURE,
UNKNOWN_ERROR = 1000,
};

Я мог бы написать структуру, которая имеет разные перегруженные конструкторы для каждого отдельного перечисления, которые могут содержать, которые все преобразуют их в int для их хранения.Но в этом случае я бы упустил возможность сравнить код ошибки с фактическими значениями перечисления позже.Мне также нужно написать оператор сравнения для каждого из возможных типов.

Я также мог бы использовать шаблоны, подобные этому:

template<typename T>
struct Error
{
  T const code;
  std::string const message;
};

Но теперь я не смог бы создать ошибку, подобную этой:

Error{NetworkErrorCode::CONNECTION_FAILURE, "some message"}.

Мне нужно написать:

Error<NetworkErrorCode>{NetworkErrorCode::CONNECTION_FAILURE, "some message"}.

Есть ли способ избежать написания большого количества кода, как в первом решении, сохраняя при этомвозможность их создания без явного указания имени типа?Я слышал о выводе аргументов шаблона для конструкторов шаблонов классов в c ++ 17, но я не могу разобраться с этим.

Ответы [ 2 ]

0 голосов
/ 25 апреля 2018
using error_code = std::variant<int, NetworkErrorCode, AnotherErrorCode /*etc*/>;

struct Error {
  error_code code;
  std::string message;
};

для этого необходимо перечислить все типы кодов ошибок в одном месте;но это меньше работы, чем написание конструкторов, которые вы хотите записать.

Error{NetworkErrorCode::CONNECTION_FAILURE, "some message"}

работает без написания дополнительных конструкторов, потому что вариант преобразует из любого из возможных типов.

Чтобы получить доступ, вы имеетеstd::visit или .get<Type>() или тому подобное.== на error_code обычно должно работать (иногда вам может понадобиться явно привести другой аргумент к error_code).

0 голосов
/ 25 апреля 2018

Что вам нужно сделать, это добавить ctor, как показано ниже:

Error(T const t, const string s)  : code(t), message(s) {}

Затем с помощью компилятора, совместимого с c ++ 17, все будет готово.

Вы можетеотметьте это на Godbolt, https://godbolt.org/g/Dyznp8

Обратите внимание, что здесь используется вычитание аргумента шаблона C ++ 17 для конструкторов шаблона класса вместо использования варианта.

Полный пример кода приведен здесь для справки.,

#include <string>
using namespace std;

enum class NetworkErrorCode {
    OK = 0,
    CONNECTION_FAILURE,
    EMPTY_RESPONSE,
    HOST_RESOLUTION_FAILURE,
    UNKNOWN_ERROR = 1000
};

template<typename T>
struct Error
{
  T const code;
  std::string const message;
  Error(T const t, const string s)  : code(t), message(s) {}
};

template <typename T>
auto getStuff() -> variant<string, Error<T>> {
    variant<string, Error<T>> w;
    return w;
}

int main() {
    int i = 2;
    if (i == 1) {
        Error{NetworkErrorCode::CONNECTION_FAILURE, "some message"};
    }
}

Вы можете скомпилировать его с помощью -std=c++17.

...