我有一些用C语言编写的旧代码,我想在C ++ 14中进行重构。我必须遇到一个我无法解决的问题。
在普通的C语言中,有一种方法可以在数组之间进行切换。
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
const int sz = (machine == 1) ? NELEMS (errors1) : NELEMS (errors2);
const struct Error *error = (machine == 1) ? &errors1[0] : &errors2[0];
上面的代码有效,但是不可读。我想使用std::array
,因为它可以用越来越少的可读性代码轻松地进行操作。 std::vector
使用堆内存,我希望结果可存储。
C ++代码三元运算符 const Error &error = (machine == 1) ? errors1 : errors2;
不能以这种方式使用,因为std::array<Error, 3> errors1
和std::array<Error, 5> errors2
是不同的类型!那么如何使用std::array
实现相同的功能?
旧版C代码
enum ErrorCode {
ERR_NOT_FOUND,
ERR_FORBIDDEN,
ERR_INTERNAL,
ERR_UNAVAILABLE,
ERR_NO_RESPONSE,
ERR_UNSUPPORTED,
ERR_OUT_OF_MEMORY,
ERR_TIMEOUT
};
struct Error {
int id;
int code;
const char *str;
};
static const struct Error errors1[] = {
{1001, ERR_NOT_FOUND, "Not Found"},
{1002, ERR_FORBIDDEN, "Forbidden"},
{1003, ERR_INTERNAL, "Internal Error"}
};
static const struct Error errors2[] = {
{1004, ERR_UNAVAILABLE, "Temporarly Unavailable"},
{1005, ERR_NO_RESPONSE, "No Response"},
{1006, ERR_UNSUPPORTED, "Unsupported"},
{1007, ERR_OUT_OF_MEMORY, "Insufficient Memory"},
{1008, ERR_TIMEOUT, "Timeout"}
};
#define NELEMS(x) (sizeof(x) / sizeof((x)[0]))
char *error_to_string (char machine, int id) {
const int sz = (machine == 1) ? NELEMS (errors1) : NELEMS (errors2);
const struct Error *error = (machine == 1) ? &errors1[0] : &errors2[0];
const char *str = "Unknown";
for (int i = 0; i < sz; i++) {
if (error[i].id == id) {
str = error[i].str;
break;
}
}
return str;
}
试图使用与C代码相同的功能来实现对C ++代码的现代化
std::array<Error, 3> errors1= {{
{1001, ERR_NOT_FOUND, "Not Found"},
{1002, ERR_FORBIDDEN, "Forbidden"},
{1003, ERR_INTERNAL, "Internal Error"}
}};
std::array<Error, 5> errors2= {{
{1004, ERR_UNAVAILABLE, "Temporarly Unavailable"},
{1005, ERR_NO_RESPONSE, "No Response"},
{1006, ERR_UNSUPPORTED, "Unsupported"},
{1007, ERR_OUT_OF_MEMORY, "Insufficient Memory"},
{1008, ERR_TIMEOUT, "Timeout"}
}};
const char *error_to_string (char machine, int id) {
const char *str = (char*) "Unknown";
const auto errors = (machine == 1) ? &errors1[0] : &errors2[0];
for (auto error : errors) {
if (error.id == id) {
str = error.str;
break;
}
}
return str;
}
答案 0 :(得分:3)
您可以使用lambda在给定数组中搜索错误。
const char *error_to_string(const char machine, const int id) {
const auto find_error = [id](const auto &errors) {
for (const Error &error : errors) {
if (error.id == id) return error.str;
}
return "Unknown";
};
return machine == 1 ? find_error(errors1) : find_error(errors2);
}
要将其扩展到许多数组,只需使用switch
。
const char *error_to_string(const char machine, const int id) {
const auto find_error = [id](const auto &errors) {
for (const Error &error : errors) {
if (error.id == id) return error.str;
}
return "Unknown";
};
switch (machine) {
case 1: return find_error(errors1);
case 2: return find_error(errors2);
case 3: return find_error(errors3);
// ...
}
// probably want to handle this properly
assert(false);
return "Invalid machine";
}
答案 1 :(得分:2)
如果您有N
个数组,而不仅仅是两个数组,那么简单的元编程可能会有所帮助:
template<char machine_id>
auto& get_errors() {
if constexpr (machine_id == 0)
return errors1;
else if constexpr (machine_id == 1)
return errors2;
...
else
return errorsN;
}
template<char machine_id>
const char* error_to_string_impl(char machine, int id) {
if (machine == machine_id) {
const auto& errors = get_errors<machine_id>();
const auto fn = [id](Error e) { return e.id == id; };
const auto it = std::find_if(errors.begin(), errors.end(), fn);
if (it != errors.end())
return it->str;
return "Unknown";
}
if constexpr (machine_id + 1 < N)
return error_to_string_impl<machine_id + 1>(machine, id);
assert(false); // unreachable
// return "Unknown machine";
}
const char* error_to_string(char machine, int id) {
return error_to_string_impl<0>(machine, id);
}
get_error
也可以通过重载来实现:
auto& get_errors(std::integral_constant<char, 0>) {
return errors1;
}
auto& get_errors(std::integral_constant<char, 1>) {
return errors2;
}
auto& get_errors(...) {
return errorsN;
}
和
const auto& errors = get_errors(std::integral_constant<char, machine_id>{});
答案 2 :(得分:2)
在C ++ 20中,有std::span
:
const char* error_to_string (char machine, int id) {
const auto errors = (machine == 1) ?
std::span<Error>{errors1} :
std::span<Error>{errors2};
for (const auto& error : errors) {
if (error.id == id) {
return error.str;
}
}
return "Unknown";
}
以前,您可以使用模板:
template <typename Container>
const char* error_to_string(const Container& errors) {
for (const auto& error : errors) {
if (error.id == id) {
return error.str;
}
}
return "Unknown";
}
const char* error_to_string (char machine, int id) {
return (machine == 1) ? error_to_string(errors1) : error_to_string(errors2);
}