Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the type of {object}?

Tags:

c++

Consider following piece of code:

void foo (M&) {}

M m;
foo ({m});

So, the expression {m} is treated as rvalue reference and that is why this code fails to compile.

Is this true that {object} always produces temporary object?

If no, then how to be sure when it happens? If yes, please consider following code:

struct M {};

struct I {
    I (M&) {}
};

struct MM {
    MM (M& p)
    : m (p), i ( {p} )
    {}

    M& m;
    I i;
};

M m;
MM mm {m};

Here there is no problem at all, so what is the difference between {m} from the first example and {p} from the second?

Compiler (GCC 4.8.1) results (first example):

main.cpp:366:13: error: invalid initialization of non-const reference of type ‘M&’ from an rvalue of type ‘<brace-enclosed initializer list>’
     foo ({m});
             ^
main.cpp:359:6: error: in passing argument 1 of ‘void foo(M&)’
 void foo (M&) {}
like image 796
Artur Pyszczuk Avatar asked Nov 24 '16 10:11

Artur Pyszczuk


1 Answers

What is the type of {object}?

That depends on the context. In some situations, such as when constructing a type with a std::initializer_list parameter, it'll be of type std::initializer_list<decltype(object)>. In others, it'll be used to initialize members of an aggregate or some other type, in which case the syntactic form {object} doesn't have a type per se.

Is this true that {object} always produces temporary object?

No, and in your case it shouldn't. This was a bug in the C++11 spec relating to the ordering of clauses specifying list initialization. The old wording meant that your call resulted in the construction of a temporary (which is ill-formed due to the non-const reference parameter), but under the new rules, the reference binds to the single initializer list element. Your old compiler implements the old wording, whereas newer compilers implement the fixed behaviour.

Here there is no problem at all, so what is the difference between {m} from the first example and {p} from the second?

The difference is that {m} is used to initialize the M parameter of foo (invalid under the old wording), but {p} initializes the I member. As such, p is taken as the argument to the I constructor, binds to the M& parameter, and since p is an lvalue, everything is fine and dandy.

like image 181
TartanLlama Avatar answered Oct 07 '22 14:10

TartanLlama