2
votes

I have some C++11 structs and classes that I'm trying to back or replace with protobufs. I have a struct that's initialized in a few places using the aggregate initialization style, like this:

  SomeStruct instance ({
    "some string",
    {"an", "array", "of", "strings",},
    SomeEnum::SomeValue,
  });

If I try to replace SomeStruct with it's corresponding protobuf, it complains that there's "no matching constructor for initialization of" SomeStructProto and "cannot convert initializer list argument to" SomeStructProto. Which makes sense, since there's no constructor for this in the generated protobuf code and the fields are private.

I'd like to modify how the code is being used as little as possible. Is there a way to build a function or helper class that would work sort of like the proper constructor? Something like this:

  SomeStruct instance = SomeStructConversionFunction ({
    "some string",
    {"an", "array", "of", "strings",},
    SomeEnum::SomeValue,
  });

This is my attempt so far, just to see if I can get it to compile:

SomeStructProto SomeStructConversionFunction(
    std::initializer_list<SomeStructProto> config) {
  return SomeStructProto();
}

but the compiler complains "no known conversion from 'const char [1]' to 'SomeStructProto' for 1st argument".

I'm pretty flexible with how the end result would work, I just don't want to end up with lots of some_struct.set_some_field("some string"). Any ideas?

1
With your 1st example I don't think the outer (round brackets) are needed. Aggregate initialisation would start with {.Richard Critten
Wouldn't it be better to invest now in wholesale change? Rather than hacking thin workarounds on top of the old design? "I just don't want to end up with lots of some_struct.set_some_field("some string")" No, you don't want that. Create and use a constructor.Lightness Races in Orbit
My advice to you would be to avoid trying to use protobuf-generated classes outside of serialization and deserialization code. Have real, hand-crafted classes to implement your program logic that have methods that return protobuf classes that you can use for persistance, or write to the network, or whatever.Miles Budnek
@MilesBudnek - I'm fine doing that, but at some point I need to copy the data over, and I'm trying to avoid the long list of proto_instance.set_member_x(real_class.get_x()), since they're prone to getting out of sync.Jay Lemmon
@BoundaryImposition - Protobufs generate their own C++ classes. You can't write your own constructors for them, and inheriting from them to add your own methods is discouraged.Jay Lemmon

1 Answers

1
votes

What you are trying to do here is aggregate intialization. Even with the latest syntax = "proto3"; version, I don't see that as a possibility. According to an issue in the protocol buffer repository:

It seems that aggregate init is not compatible with the primary goals of protobuf. Namely provide a stable back and forwards compatible extensible protocol, both on the wire and as a programming library.

So the encouraged solution here would be to create wrapper classes for your messages, to which you will be able to write aggregate initialization. Creating wrapper classes are a good idea also in the perspective of creating more complicated utilies for your messages If needed.