4

EDIT: I don't think this a duplicate of this other question, because the other question simply transposes () for {} in the constructors. Whereas I note different behavior when a constructor is defined in a struct, but not in a class. (And, as pointed out in the comments, this is about using constructors not writing them.) But I've been wrong before.

I came across this strange (to me) syntax for a constructor while tutoring:

Foo obj {i, j};

At first I thought it wouldn't work, and told the student to rewrite it – however they were adamant it worked, and informed me they pulled the example from cplusplus.com, to which I've not been able to find a reference, so I tried it anyway... And it worked. So I experimented with it.

I also researched a bit on my own, and found no reference to that kind of constructor syntax on cplusplus.com. (Maybe it has a specific name?)

Here's what I did to experiment with it.

struct Note { //A musical note.
    std::string name;
    double freq;
    //Note(std::string s, double f): name(s), freq(f){}
    //Uncomment the constructor in order to use normal constructor syntax.
};

class Journal {
public:
    std::string title;
    std::string message;
    int idNum;
};

int main() {
    Note a { "A", 440.0}; //Works with or without a constructor.
    //Note a("A",440.0); //Works ***only*** with a defined constructor.

    //Journal journal("hello, world", "just me, a class", 002); //Works regardless of constructor definition.
    Journal journal {"hello, world", "just me, a class", 003}; //Works regardless of constructor definition.

    std::cout << a.name << " " << a.freq << std::endl;
    std::cout << journal.title << " " << journal.message << " " << journal.idNum << std::endl;

    return 0;

}

I found that it works with structs and classes regardless if they have a defined constructor.

Obviously default constructors are at work, but this confused me because of a few reasons:

  • I've never seen this syntax before (not surprising, C++ is huge)
  • It actually works
  • Works regardless of a constructor being defined, so may be default behavior

My question is:

  • Is there a name and specific purpose for this syntax which sets it apart from regular constructor behavior, and if so, why use it (or not)?
Marco A.
  • 43,032
  • 26
  • 132
  • 246
NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • 2
    It's called [uniform initialization](http://stackoverflow.com/questions/tagged/uniform-initialization). – zdan Oct 28 '16 at 19:04
  • 1
    Little used is a big stretch. You might want to look for [uniform initialization](http://www.stroustrup.com/C++11FAQ.html#uniform-init). It has been a part of the language for half a decade now. – krzaq Oct 28 '16 at 19:04
  • Thanks for the references! – NonCreature0714 Oct 28 '16 at 19:09
  • 4
    This question is not a duplicate of http://stackoverflow.com/questions/26804312/initializer-list-syntax-in-member-initializer-list-c11 because that question is about writing a constructor, and this question is about using constructors. – David Grayson Oct 28 '16 at 19:11

2 Answers2

3

Things have changed since the introduction of C++11 and you should probably read about list initialization

int x (0);  // Constructor initialization
int x {0};  // Uniform initialization

Before its introduction you had various initialization cases:

  • objects by calling the usual () constructor (and watch out for most vexing parse if no arguments are present)
  • aggregate classes or arrays with {}
  • default constructing with no braces

Now you can use uniform initialization in all of them.

It has to be noted that the two aren't really interchangeable since

std::vector<int> v (100); // 100 elements
std::vector<int> v {100}; // one element of value 100

and you have to pay attention to the fact that if the type has an initializer list constructor, it will take precedence in overload resolution.

That said, uniform initialization can be quite handy and safe (preventing narrowing conversions).

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
2

That syntax is called "list initialization". You can read more about it in Section 8.5.4 of C++14.

I would guess that this syntax mainly exists to be backwards compatible with C, which had syntax for initializing structs and arrays that looked very similar.

David Grayson
  • 84,103
  • 24
  • 152
  • 189
  • 5
    That syntax is **not** compatible with C (in C it would be `struct Foo obj = {i, j};`). Looking similar has never been a driving factor. The syntax exists to not collide with any other legal construct in C++. And it needed a new syntax, because it has stricter semantics (e.g. no narrowing conversions). – IInspectable Oct 28 '16 at 19:29