protobuf: 重复字段的唯一元素

4
我希望在Google协议缓冲区中,repeated field中只有唯一的元素。换句话说,需要将其用作std::set而不是std::vector
有什么简单有效的方法吗? 编辑:如果可能的话,我不想使用任何迭代器来循环遍历所有元素。

1
Google的protobuf在它们的接口中不支持那么细致的细节。你可以修改源代码,但那似乎是浪费时间的巨大工作。迭代所有元素并将它们添加到一个集合中可能是最好的解决方案。 - Josh
谢谢,那证实了我的发现 :) - Alex
你的代码是否受到Google Protobuf的限制,或者你可以使用其他工具包? - Josh
虽然 gpb 受到很大的限制,无法创建精确的 API,但我认为这种简单性也有其优势。通过查看明文 protobuf 定义,我们可以非常容易地理解它在做什么。如果使用复杂的 XML 模式进行定义,你可能会迷失数日! - Josh
2个回答

2
好的,正如问题评论所述,没有使用迭代器的方法来完成这个任务。但是,也许其他人会感兴趣,这里是我编写的函数来实现这个目标。该函数需要作为参数一个RepeatedPtrField< T >*(列表)和一个std::string(我们打算添加到列表中的新对象的键),并返回与该id相匹配的元素,如果在RepeatedField列表中找不到具有此键的条目,则返回NULL
这样,您可以直接在RepeatedField中轻松地保留唯一元素的列表,而不使用任何其他std结构:
template <class T>
T* repeatedFieldLookup( google::protobuf::RepeatedPtrField< T >* repeatedPtrField, std::string id)
{
   google::protobuf::internal::RepeatedPtrOverPtrsIterator<T> it = repeatedPtrField->pointer_begin();
   for ( ; it != repeatedPtrField->pointer_end() ; ++it )
   {
      CommonFields * commonMessage = (CommonFields*) (*it)->GetReflection()->
     MutableMessage ((*it), (*it)->GetDescriptor()->FindFieldByName ("common"));
      if(commonMessage->id() == id)
      {
     return *it;
      }
   }
   return NULL;
}

注意:在上面的示例中,proto消息将始终具有名为common(在我的情况下也是proto消息)的字段。您可以用任何您想要的东西替换它,以便比较您的proto消息。


0
在我有这个类的情况下:
class Description : public ::google::protobuf::Message {
  // ...
  inline void add_field(const ::std::string& value);
  inline const ::google::protobuf::RepeatedPtrField< ::std::string>& field() const;
  // ...
};

我使用了 std::find 来判断列表中是否存在该值,以便仅在该值不存在时添加它:

#include <algorithm>

void addField(Description& description, const std::string& value) {
    const auto& fields = description.field();
    if (std::find(fields.begin(), fields.end(), value) == fields.end()) {
        description.add_field(value);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接