如何从 protobuf 中的枚举中获取下一个枚举值?

How to get the next enum value from an enum in protobuf?

我有一个带有非连续枚举值的 protobuf 消息,如下所示:

message Information {
    enum Versions {
        version1 = 0;
        version2 = 1;
        version3 = 10;
        version4 = 20;   
        version5 = 30;    
    }
}

我想要一个 C++ 函数 GetNextVersion(),它接受一个枚举版本并给出下一个版本作为输出。例如:GetNextVersion(Information::version4) 应该给出 Information::version5 作为输出。有没有内置的简单方法可以做到这一点?

Is there any inbuilt and easy method to do this?

我认为没有简单的方法可以做到这一点。

但我可以建议 metaprogramming 使用 C++ 代码生成的方法(至少在 Linux 上)。

你可以,假设你可以访问 source code of protobuf-c :

  • 编写一些GNU gawk脚本来解析该C++代码并生成GetNextVersion

    的C++代码
  • 也许写一些 GNU sed (or a Python 一个) 脚本做同样的事情。

  • 写一些GCC plugin并用它来解析那个C++代码并生成GetNextVersion

    的C++代码
  • 写一些 GNU emacs 代码来做同样的事情。

  • 再等几个月(在 spring 2021 年)使用 Bismon。我正在开发它,请通过电子邮件与我联系

  • 根据您的需要扩展和调整 Clang static analyzer

  • 根据您的需要扩展和调整 SWIG 工具。

  • 根据您的需要扩展和调整 RPGGEN 工具。

  • 使用 GNU bison or ANTLR to parse C++ code, or design your domain specific language with some documented EBNF 语法并用它们编写一些代码生成器。

您还可以在某些数据库中保留 enum Versions 的描述 (sqlite, PostGreSQL, etc...) or some JSON file or some CSV file (or an XML one, using XSLT or libexpat) and emit it (for protobuf) and the source code of GetNextVersion using some Python script, or GNU m4, or GPP.

您可以编写 GNU guile script or some rules for CLIPS 生成一些带有您的 protobuf 描述的 C++ 代码。

几个月后(spring 2021 年),RefPerSys 系统可能会有所帮助。在此之前,您可以贡献和扩展它并根据您的需要重用它。

一种实用的方法是在您的 protobuf 声明中添加注释,以提醒您在需要更改 protobuf 消息和协议时编辑另一个文件。

可以使用protobuf的反射来达到目的:

Information::Versions GetNextVersion(Information::Versions ver) {
    const auto *desc = Information::Versions_descriptor();
    auto cur_idx = desc->FindValueByNumber(ver)->index();
    if (cur_idx >= desc->value_count() - 1) {
        throw runtime_error("no next enum");
    }

    auto next_idx = cur_idx + 1;
    return Information::Versions(desc->value(next_idx)->number());
}

int main() {
    try {
        auto ver = Information::version1;
        while (true) {
            cout << ver << endl;
            ver = GetNextVersion(ver);
        }
    } catch (const runtime_error &e) {
        cout << e.what() << endl;
    }
    return 0;
}

没有,没有。

您定义自己的数据类型,因此您还必须为其定义运算符。

因此,您的 GetNextVersion() 方法包含如何增加版本号的知识。如果您决定使用整数,那么编译器已经知道如何增加它,但是您想要一些特别的东西,这就是您必须为此付出的代价。