gpt4 book ai didi

c++ - 在 C++ 中,如何创建值为 protobuf 扩展标识符的映射

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:55:33 26 4
gpt4 key购买 nike

在protobuf中,我们有几个选项来实现继承。 “嵌套扩展”就是其中之一: http://www.indelible.org/ink/protobuf-polymorphism/

这里有趣的是如何读取序列化文件。我们必须创建一个 Map 以将 Animal.type 与其扩展标识符相对应,以便将动物转换为正确的 Dog 或 Cat。但是,在上面网站提供的示例中,使用的语言是Python。这意味着可以在不指定键类型或值类型的情况下初始化 Map。而且效果很好:

# Unpack the serialized bytes.
animal = Animal()
animal.ParseFromString(bytes)

# Determine the appropriate extension type to use.
extension_map = { Animal.Cat: Cat.animal, Animal.Dog: Dog.animal }
extension = animal.Extensions[extension_map[animal.type]]

但是,为了在C++中实现这样的映射,键类型和值类型是强制性的。那么,我应该使用什么类型的值才能将两个不同的扩展标识符存储到同一个映射中?

Map<Animal::Type, ::google::protobuf::internal::ExtensionIdentifier>

不幸的是,这显然行不通。

我还要在这里复制粘贴写作范式: 从 animals_pb2 导入 *

# Construct the polymorphic base message type.
animal = Animal()
animal.type = Animal.Cat

# Create the subclass type by referencing the appropriate extension type.
# Note that this uses the self-referential field (Cat.animal) from within
# nested message extension.
cat = animal.Extensions[Cat.animal]
cat.declawed = True

# Serialize the complete message contents to a string. It will end up
# looking roughly like this: [ type [ declawed ] ]
bytes = animal.SerializeToString()

Extensions() 函数可以让我们使用扩展的标识符来获取它的扩展。

最佳答案

如果我对问题的理解正确,您希望将构造的扩展对象的映射存储在映射中,以便在解析消息后访问。

在这种情况下,有 variantany在 boost 中键入,poco libraries还有一些。您可以使键类型固定(即枚举类型或字符串),并将值类型设为变体类型:

#include <boost/any.hpp>
#include <map>
#include <iostream>
#include <string>
#include <memory>

struct Animal {
std::string type;
};

struct Dog : public Animal {
constexpr static const char* TYPE = "Dog";
void bark() const {
std::cout<<"bow"<<std::endl;
}
};

struct Cat : public Animal {
constexpr static const char* TYPE = "Cat";
void meow() const {
std::cout<<"meow"<<std::endl;
}
};

从消息中获取扩展的工厂:

template <typename Animal,typename Message>
std::unique_ptr<Animal> get_extension(Message m) {
try {
Animal a( boost::any_cast<Animal>(m[Animal::TYPE]) );
//for simplicity
return std::unique_ptr<Animal>(new Animal(a));
} catch (...) {
return std::unique_ptr<Animal>();
}
}

和用法:

int main()
{
// simulation of a protobuf message
std::map<std::string,boost::any> m;
m[Dog::TYPE] = Dog();
m[Cat::TYPE] = Cat();

// the generic interface to the message extensions
auto dog = get_extension<Dog>(m);
if (dog)
dog->bark();
auto cat = get_extension<Cat>(m);
if (cat)
cat->meow();
}

compile@coliru

更新:version 2具有动物通用界面

实际任务可能是您有一 strip 有扩展名的消息,并且您想要动态创建对象。在第二个版本中,您还可以通过相同的界面“与动物交谈”:

struct Animal {
virtual void speak() const = 0;
virtual ~Animal(){}
};

struct Dog : public Animal {
constexpr static const char* TYPE = "Dog";
virtual void speak() const {
std::cout<<"bow"<<std::endl;
}
};
// ... etc

类型反序列化动物的简单工厂:

struct AnimalRegistry {
std::map<std::string , std::function<std::unique_ptr<Animal>()>> creators;

template<typename A>
void register_creator() {
creators[A::TYPE] = []() { return std::unique_ptr<Animal>(new A); };
}

template<typename Message>
std::unique_ptr<Animal> create(Message m) {
return creators[m.animal_type]();
}
};

用法略有不同:

int main()
{
AnimalRegistry registry;
registry.register_creator<Dog>();
registry.register_creator<Cat>();

Message received_message { "Dog" /*this is a part of your protobuf*/ };

auto dog = registry.create(received_message);
if (dog)
dog->speak();

Message another_message { "Cat" };
auto cat = registry.create(another_message);
if (cat)
cat->speak();
}

关于c++ - 在 C++ 中,如何创建值为 protobuf 扩展标识符的映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19975595/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com