4

I like the new automatically generated brace-enclosed initializers!

Is there any way I can avoid losing them if I start to declare my own constructors?

Code

#include <string>

struct Foo
{
    int          i;
    std::string  s;

    // Foo() { }  // I lose my brace-enclosed initializers if I uncomment this line
};

int
main( int argc, char* argv[] )
{
    Foo f{ 1, "bar" };  // having the option to do this is good

    return 0;
}

ANSWER

In light of juanchopanza's answer below, it looks like I must satisfy the lengthy rules for aggregates. But I still need a solution that I can apply to 50+ ORM classes (most with 5-15 fields each) that doesn't require a ton of boiler-plate code, or if there is boiler-plate code, at least it should be easy to edit/maintain.

The closest I could get was this solution using composition. I wonder if there is something better/simpler...

#include <string>

// this class must satisfy the rules for aggregates
struct Foo_
{
    int          i;
    std::string  s;
};

// this class can be anything...
struct Foo
{
    Foo_         m_f;
    Foo( Foo_ const& f ) : m_f( f ) { }
};

int
main( int argc, char* argv[] )
{
    Foo  f( { 1, "bar" } );   // ugly, but works

    return 0;
}
Community
  • 1
  • 1
kfmfe04
  • 14,936
  • 14
  • 74
  • 140
  • 2
    This is not new and there is no constructor, nor initializer lists involved. Aggregate initialization has existed since ever. – R. Martinho Fernandes Dec 20 '12 at 20:50
  • @ildjam ty for your comment - is there any way I can generate one more automatically (maybe using c++11 functionality)? I have like 50 database struct-related ORM classes - it's going to be painful hand-coding each one with 5-10 fields each, especially when the compiler knows how to do it... – kfmfe04 Dec 20 '12 at 20:50

1 Answers1

7

You cannot avoid losing the automatic aggregate initialization because your class is no longer an aggregate. But you can add a constructor taking two parameters, and benefit from aggregate initialization for non-aggregates:

struct Foo
{
    int          i;
    std::string  s;
    Foo(int i, const std::string& s) : i(i), s(s) {}
    Foo() = default; // idiomatic C++11
};
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • that `default` is interesting - could I do this? `Foo( int i, const std::string&s ) = default;`? or something even shorter? Looks like the compiler doesn't like it... – kfmfe04 Dec 20 '12 at 20:52
  • @kfmfe04 No, you can't do that. It only works for the "special" functions (copy and assignment operators, destructor, default constructor). – juanchopanza Dec 20 '12 at 20:54
  • what's bugging me is simply because I add a constructor, I now have to hand-code what the compiler knows how to generate! ARGH! – kfmfe04 Dec 20 '12 at 20:55
  • 1
    @kfmfe04 the logic of this particular corner of the language is that, once you define one constructor, the compiler can no longer safely know how to provide the others. – juanchopanza Dec 20 '12 at 20:56
  • I could tell the compiler by adding the `default` like you mentioned - but for some reason, that is not allowed... ...hmm... maybe I can try containment or some other pattern – kfmfe04 Dec 20 '12 at 20:59