Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does braced-init-list behave differently in a function call versus a constructor invocation?

Compiling the following code with clang 3.5.0 and gcc 4.9.1 yields an error at the last statement.

#include <iostream>

struct Foo { Foo(int x, int y) { std::cout << "Foo(int = " << x << ", int = " << y << ")" << std::endl; } };

void bar(int x, int y) { std::cout << "bar(int = " << x << ", int = " << y << ")" << std::endl; }

int main()
{
   Foo({}, {});   // Foo(int = 0, int = 0)
   Foo({1}, {2}); // Foo(int = 1, int = 2)
   Foo({1, 2});   // Foo(int = 1, int = 2)

   bar({}, {});   // bar(int = 0, int = 0)
   bar({1}, {2}); // bar(int = 1, int = 2)
   bar({1, 2});   // error: no matching function for call to 'bar'  <<< Why? <<<
}

Why is Foo({1, 2}) okay while bar({1, 2}) is not?

Particularly, it would be great to learn about the rationale.

like image 286
precarious Avatar asked Nov 07 '14 16:11

precarious


2 Answers

Foo({1,2}) creates a temporary Foo object and calls the copy constructor.

See this modified example with copy constructor delete: http://coliru.stacked-crooked.com/a/6cb80746a8479799

It errors with:

main.cpp:6:5: note: candidate constructor has been explicitly deleted
    Foo(const Foo& f) = delete;
like image 144
Borgleader Avatar answered Nov 14 '22 23:11

Borgleader


The line

bar({1, 2});

actually passes in the bar function, a temporary object of type

<brace-enclosed initializer list> // it's made clear in the comments that brace initializers have no type

and there is no way to convert this temporary object to the type of the first argument which is an int. Thus the error

cannot convert <brace-enclosed initializer list> to int for argument 1 to

void bar(int, int)
like image 26
Lorah Attkins Avatar answered Nov 14 '22 21:11

Lorah Attkins