Archived

This forum has been archived. Please start a new discussion on GitHub.

C++ mapping: availability of constructor with field parameters for structs

Hi all,

Section 6.7.2 of the Ice User Manual states the following:

Structures also have a second constructor that has one parameter for each data member. This allows you to construct and initialize a class instance in a single statement (instead of first having to construct the instance and then assigning to its members).

However, if I use the standard 'struct as struct' C++ mapping, this second constructor appears not to be generated in Ice 3.4.0.

I am really in need of this functionality. Is this a bug or will the second constructor only be generated in "[cpp:class]" mode by design?

Regards, Sidney

Comments

  • mes
    mes California
    Hi,

    That's a bug in the documentation. The C++ mapping for non-class structures has never generated a "one-shot" constructor because you can use aggregate initialization in this case. For example:
    // Slice
    struct S
    {
        string name;
        int count;
    };
    
    // C++
    S s = { "joe", 5 };
    
    We'll clear this up in the next release.

    Regards,
    Mark
  • Hi Mark,

    There's some things one can do with a "real" constructor that one cannot do with an aggregate initialization - the aggregate initialization is only usable when declaring a named variable, thereby preventing use of the struct as a "rhs-value". This prevents real-life uses, eg.
    return RGBColor(255,0,0); // won't work
    
    // must instead be written as
    RGBColor red = {255,0,0};
    return red;
    

    In the RGBColor example, this isn't too bad, but if you have deeply nested structs, this solution becomes problematic. In that case, it is hard to see what's going on without the typename information provided by a true constructor call.

    In short, I would argue in favor of generating proper constructor boilerplate code also for structs in the C++ mapping. I hope you are willing to consider this.

    - Sidney
  • mes
    mes California
    Hi,

    The goal of the C++ mapping for structures was to preserve their status as a POD type. If we added a one-shot constructor, we would not only remove this quality but also potentially break backward compatibility with existing applications. I think the only way it would be feasible would be with the use of a new metadata tag.

    Regards,
    Mark
  • Hi Mark,
    mes wrote: »
    The goal of the C++ mapping for structures was to preserve their status as a POD type.
    Yes, that is a desirable property and I fully agree that you shouldn't do anything to break that.

    Just to make sure we're talking about the same thing, Id' basically like to have something like this, perhaps defined inline (inside the class declaration) to ensure zero overhead:
    RGBColor(const Ice::Byte & _r, const Ice::Byte & _g, Ice::Byte & _b) :
        r(_r), g(_g), b(_b) {}
    

    I don't see how adding such a constructor, that takes values for all member fields, would break the "PODness", so to speak. A user would in no way be obliged to use the "initialize-all-fields-by-parameter" constructor; and you already define parameterless default constructors.
    If we added a one-shot constructor, we would not only remove this quality but also potentially break backward compatibility with existing applications.
    As stated above, I don't think you would take anything away from the POD-ness of the struct (everything that worked before will still work). And after a bit of thinking I cannot come up with any case that could lead to breaking backward compatibility, myself, so I'm curious about things that could go wrong there.
  • mes
    mes California
    Hi,

    As stated on the Wikipedia page, POD types cannot have user-defined constructors.
    you already define parameterless default constructors
    We only define a default constructor for a non-class structure when at least one of its members declares a default value. The constructor is unavoidable in this case, and losing the POD-ness of the type is the price you pay for the convenience of the default values. There would be no harm in adding a one-shot constructor in this case, and we'll probably do that in the next release.

    Regards,
    Mark
  • Hi Mark,

    You are right, I overlooked the union case -- nasty.

    If you add the one-shot constructor in case you make a default constructor anyway (in case of default values), that would be pretty useful I think.

    Best regards, Sidney
  • Umm.. what about using this compiler directives for your structures:

    ["cpp:class"] struct MyStruct { };
  • chow: this would have significant impact on the code.

    As far as I can tell, exchanging classes over an interface implies implementation and registering of a factory, incurs a slight performance penalty, and implies that the classes are to be used via Ice's shared pointer mechanism.

    While this may or may not be a good idea in it self, it differs significantly from the way structs are supported by the C++ runtime. All I need, really, is all-member constructors for the structs.
  • bernard
    bernard Jupiter, FL
    Hi Sidney,

    The "[cpp:class]" metadata suggested Brian, and that you mentioned in your first post, is not the same as replacing your Slice 'struct' by a Slice 'class'. In particular, there would be no factory generated or implemented/registered by you.

    With "[cpp:class"], you'd get Ptrs and ref-counted objects, instead of structs passed by value/reference. And this was indeed the motivation for adding this metadata: handling structs as Ptrs is more efficient in some situations.

    Best regards,
    Bernard
  • I stand corrected, a little bit of confusion on my side... Thanks.

    Sidney