0

Suppose I have a class

class Widget
{
public:
    explicit Widget();
    explicit Widget(int foo, int bar);

private:
    Gadget * gadget_;
    int foo_{42};
    int bar_{13};
}

with constructors that use some members (therefore initialization order is important):

Widget::Widget()
{
    ComplicatedConstructionStandIn::frobnicate_gadget(&gadget_);
    TheConstructorHasManyLines(foo_, gadget_);
    ItDoesMultipleThings(bar_);
}

Widget::Widget(int foo, int bar)
    : foo_{foo}
    , bar_{bar}
{
    ComplicatedConstructionStandIn::frobnicate_gadget(&gadget_);
    TheConstructorHasManyLines(foo_, gadget_);
    ItDoesMultipleThings(bar_);
}

Clearly, the second constructor is code duplication so you would think to delegate !BUT! you can't do that if you also want the default member initialization (int foo{42};). By delegation I mean something like this (does not compile):

Widget::Widget(int foo, int bar)
    : foo_{foo}
    , bar_{bar}
    , Widget()
{}

Is there an elegant way out of this? Wrapping the body of the constructor in an auxiliary init function is just kicking the question down the line.

Jan Hošek
  • 187
  • 1
  • 9
  • 1
    Please post a [mre] that we can copy, paste and test. – Paul Sanders Jun 14 '22 at 11:39
  • "elegant" is subjective. Given that delegating requires the constructor to be the only entry in the member initializer list imho your original code is already an elegant solution – 463035818_is_not_an_ai Jun 14 '22 at 11:43
  • 1
    Code duplication is to be avoided, but don't be afraid to call the same function twice. I doubt that a more "elegant" solution can require less code. I'd rather initialize `gadget` also in the member initializer list. – 463035818_is_not_an_ai Jun 14 '22 at 11:44
  • 1
    `Gadget* ComplicatedConstructionStandIn::frobnicate_gadget()` <-- something like that would solve this particular example. Then you can use it in the member variable defining declaration `gadget_{ComplicatedConstructionStandIn::frobnicate_gadget()};` – JohnFilleau Jun 14 '22 at 11:45
  • 1
    You need to specify the default somewhere else, but you can go with a single constructor only this way: `explicit Widget(int foo = 42) : foo_(foo){ ComplicatedConstructionStandIn::frobnicate_gadget(&gadget_); }` – fabian Jun 14 '22 at 11:46
  • @463035818_is_not_a_number Imagine `ComplicatedConstructionStandIn::frobnicate_gadget(&gadget_);` is 50 lines long (as it's name suggests). – Jan Hošek Jun 14 '22 at 11:46
  • 2
    @JanHošek if it's 50 lines long wrap it in a convenience function – JohnFilleau Jun 14 '22 at 11:47
  • 1
    @JanHošek so what? As I said, duplication is not in the function, the duplication is that you call the same function twice, and thats just what functions are made for. In case you mean its not just a function call, but 50 lines in the body of the constructor, then ... place those 50 lines inside a function ;) – 463035818_is_not_an_ai Jun 14 '22 at 11:47
  • 2
    In `Widget` I'd make a private `static std::unique_ptr make_gadget() { /*50 lines*/ }` and use that to *in situ* initialize the member variable `std::unique_ptr gadget_{ make_gadget() };`. And change the member variable to be a **unique_ptr**. – Eljay Jun 14 '22 at 11:57
  • Some eager beaver closed this not even ten minutes after asking with vaguely-related "duplicates", neither of which mention default member initializers and while I was in the middle of adding detail to respond to early comments. I don't think this is a bad question and the unique combination of default member initialization and constructor delegation hasn't been asked before AFAICT. Please reopen if only so more discussion can be had. Much worse questions get asked. – Jan Hošek Jun 14 '22 at 12:26
  • `Widget::Widget(int foo = 42, int bar = 13)`. – n. m. could be an AI Jun 24 '22 at 17:14

0 Answers0