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

C++ 在C++;,如何创建值为protobuf扩展标识符的映射,c++,inheritance,map,key,protocol-buffers,C++,Inheritance,Map,Key,Protocol Buffers,在protobuf中,我们有几个选项来实现继承。“嵌套扩展”是其中之一: 这里有趣的是如何读取序列化文件。我们必须创建一个映射,使Animal.type与其扩展标识符相对应,以便将动物转换为正确的狗或猫。但是,在上面网站提供的示例中,使用的语言是Python。这意味着可以在不指定键类型或值类型的情况下初始化映射。而且效果很好: # Unpack the serialized bytes. animal = Animal() animal.ParseFromString(bytes) # De

在protobuf中,我们有几个选项来实现继承。“嵌套扩展”是其中之一:

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

# 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++中实现这样的映射,键类型和值类型是强制性的。那么,为了将两个不同的扩展标识符存储到同一个映射中,我应该使用什么类型的值呢

地图

不幸的是,这显然不起作用

我还将在此处复制粘贴写作范例: 从动物_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()

函数的作用是:使用扩展的标识符获取扩展

如果我正确理解了这个问题,那么您希望将构造的扩展对象的映射存储在一个映射中,以便在解析消息后可以访问该映射

在这种情况下,boost中有和类型,还有更多。您可以将键类型设置为固定类型(即枚举类型或字符串),将值类型设置为变量类型:

#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;
    }
};
#包括
#包括
#包括
#包括
#包括
结构动物{
std::字符串类型;
};
结构狗:公共动物{
constexpr static const char*TYPE=“Dog”;
空树皮常数{

std::coutIf如果你想得到一个Dog实例,你必须从boost::any转换为Dog。这意味着你应该已经知道boost::any类型对应的确切类型。例如,如果你读了别人创建的对象,你几乎不知道你应该将boost::any类型转换为哪种类型。在我提供的示例中,它可以自动转换使用ExtensionIdentifier和Extensions()自动强制转换对象函数,@ pppTime+C++编译时定义类型。在C++中,如果你想使用一个类型的接口,你需要知道调用的类型。我不认为你的评论和我的解决方案有矛盾。我会尝试展示一个简单的工厂代码,这样你就明白我的意思。你试图评论:是的,你需要知道THA。t'dog'属于“dog”类型。那么您如何调用方法“dog::bark”?这是一种静态类型的语言。如果您想使用单个接口,请使用Animal作为接口,并根据注册的类型动态创建对象。这与您的需要仍然没有矛盾。下面是()进一步的示例,仍然没有“if dog then dog if cat then cat”。“if”检查消息转换是否成功,而不是检查类型。它是从消息本身推断出来的。你是对的。转换成功只是意味着它是狗类型,而不是猫类型,对吗?你是对的,无论如何,我们应该知道我们处理的所有类型,以便能够使用它。
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();
}
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();
}