41

What is this called?

Vec3 foo = {1,2,3};

Can it be controlled via an operator or some such? As in can I specify how this should act?

For instance if I had some complicated class could I use this to assign variables? (Just an exercise in curiosity).

  • 5
    I don't feel like writing this up or finding a duplicate, but in C++11, in contrast to Nawaz's excellent answer, that syntax is can be caught by initializer list constructors, and it can indeed be used for assignment by using it to initialize a temporary. http://ideone.com/RwLop – Potatoswatter Apr 14 '11 at 17:48

2 Answers2

54

That is not assignment. That is initialization.

Such initialization is allowed for aggregate only, that includes POD class. POD means Plain Old Data type.

Example,

//this struct is an aggregate (POD class)
struct point3D
{
   int x;
   int y;
   int z;
};

//since point3D is an aggregate, so we can initialize it as
point3D p = {1,2,3};

See the above compiles fine : http://ideone.com/IXcSA

But again consider this:

//this struct is NOT an aggregate (non-POD class)
struct vector3D
{
   int x;
   int y;
   int z;
   vector3D(int, int, int){} //user-defined constructor!
};

//since vector3D is NOT an aggregate, so we CANNOT initialize it as
vector3D p = {1,2,3}; //error

The above does NOT compile. It gives this error:

prog.cpp:15: error: braces around initializer for non-aggregate type ‘vector3D’

See yourself : http://ideone.com/zO58c

What is the difference between point3D and vector3D? Just the vector3D has user-defined constructor, and that makes it non-POD. Hence it cannot be initialized using curly braces!


What is an aggregate?

The Standard says in section §8.5.1/1,

An aggregate is an array or a class (clause 9) with no user-declared constructors (12.1), no private or protected non-static data members (clause 11), no base classes (clause 10), and no virtual functions (10.3).

And then it says in §8.5.1/2 that,

When an aggregate is initialized the initializer can contain an initializer-clause consisting of a brace-enclosed, comma-separated list of initializer-clauses for the members of the aggregate, written in increasing subscript or member order. If the aggregate contains subaggregates, this rule applies recursively to the members of the subaggregate.

[Example:

struct A 
{
   int x;
   struct B 
   {
      int i;
      int j;
   } b;
} a = { 1, { 2, 3 } };

initializes a.x with 1, a.b.i with 2, a.b.j with 3. ]
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 1
    You say that it's POD-only, but your compiler complains about non-aggregate. So, can an aggregate class which is not POD be initialized in this way? Yes it can. – Steve Jessop Apr 14 '11 at 16:34
  • You should also give an example that uses arrays. – Martin York Apr 14 '11 at 17:43
  • 1
    This is good, but it would be nice if you at least mentioned C++11 initialization syntax. ;-) – Omnifarious Aug 25 '11 at 15:22
  • 2
    Do you know, is there any difference between following two statements: std::vector data {1, 2, 3}; std::vector data = {1, 2, 3}; – MeJ Mar 16 '14 at 09:10
  • 2
    @MeJ: Practically, no difference. Pedantically, first one is direct initialization and the second one is copy initialization. – Nawaz Mar 16 '14 at 09:12
  • But both calls the sequence constructor, because the sequence constructor has a higher priority as the copy constructor, true? – MeJ Mar 16 '14 at 09:13
  • Compiles fine with MSVC2013, btw (must be MS changing the rules again). – mlvljr Oct 22 '15 at 11:57
  • vector3D p = {1,2,3}; compiles fine for me – simplename Feb 21 '22 at 23:28
1

To answer your question directly and briefly.

The assignment via curly braces is called "direct assignment" and it has its own rules.

If the right operand is a braced-init-list

if the expression E1 has scalar type, the expression E1 = {} is equivalent to E1 = T{}, where T is the type of E1. the expression E1 = {E2} is equivalent to E1 = T{E2}, where T is the type of E1.

if the expression E1 has class type, the syntax E1 = {args...} generates a call to the assignment operator with the braced-init-list as the argument, which then selects the appropriate assignment operator following the rules of overload resolution. Note that, if a non-template assignment operator from some non-class type is available, it is preferred over the copy/move assignment in E1 = {} because {} to non-class is an identity conversion, which outranks the user-defined conversion from {} to a class type.

Reference: https://en.cppreference.com/w/cpp/language/operator_assignment

sanjivgupta
  • 396
  • 3
  • 12