有没有办法在std :: array之间切换

我有一些用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> errors1std::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,"Internal Error"}
}};

std::array<Error,5> errors2= {{
    {1004,    {1005,    {1006,    {1007,    {1008,"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;
}
sinkysahine 回答:有没有办法在std :: array之间切换

您可以使用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";
 }
,

如果您有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>{});
,

在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);
}
本文链接:https://www.f2er.com/3059810.html

大家都在问