Copy constructor gets called instead of inizialier_list<> constructor

Hello.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
struct Foo 
{
	Foo() 
	{
		cout << "default ctor" << endl;
	}

	Foo(std::initializer_list<Foo> ilist) 
	{
		cout << "initializer list" << endl;
	}

	Foo(const Foo& copy)
	{
		cout << "copy ctor" << endl;
	}
};

int main()
{
	
	Foo a;
	Foo b(a); 

	// This calls the copy constructor again! Shouldn't this call the initializer_list constructor?
	Foo c{b}; 
	


	_getch();
	return 0;
}


The output is:

>default ctor
>copy ctor
>copy ctor

Why? Shouldn't the last have been "initializer list"?

Confused.

Last edited on
In the second link you provided, there's an answer that gives this example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
struct Foo 
{
	Foo() 
	{
		cout << "default ctor" << endl;
	}

	Foo(std::initializer_list<Foo> ilist) 
	{
		cout << "initializer list" << endl;
	}

	Foo(const Foo& copy) 
	{
		cout << "copy ctor" << endl;
	}
};

int main()
{
	Foo a;
	Foo b(a); 
	Foo c{ a }; 


	_getch();
	return 0;
}


The output is:

>default ctor
>copy ctor
>copy ctor

In this case, why didn't the initializer_list<Foo> constructor get called?
And how to call it?
Starting from http://en.cppreference.com/w/cpp/language/initializer_list

The first form "initializes the base or member named by class-or-identifier using direct initialization", linking to http://en.cppreference.com/w/cpp/language/direct_initialization

The second form "Initializes the base or member named by class-or-identifier using list-initialization (which becomes ... aggregate-initialization when initializing an aggregate)", linking to http://en.cppreference.com/w/cpp/language/list_initialization

There are many minor differences, but the one that is relevant to your choice of types is this:
list-initialization limits the allowed implicit conversions by prohibiting the following:
* conversion from a floating-point type to an integer type


which is why this compiles:
1
2
3
S(float xcoord, float ycoord) : x(xcoord), y(ycoord)
{
}
but this does not
1
2
3
S(float xcoord, float ycoord) : x{xcoord}, y{ycoord}
{
}
Last edited on
@Cubbi

the code all compiles, because i'm explicitly converting the floating-point number to a float

 
S b{ 10.5f , 20.5f };


But I don't understand why the brace-initialization calls the copy constructor in the case above :/
Last edited on
because i'm explicitly converting the floating-point number

no, it compiles because you used round parentheses in the member initializer list, which allow float to int conversion.

Now the code in the initial post changed, so this is no longer relevant. With regards to its latest iteration, Foo c{b};, http://en.cppreference.com/w/cpp/language/list_initialization has the rule:
If T is a class type and the initializer list has a single element of the same or derived type (possibly cv-qualified), the object is initialized from that element (... by direct-initialization for direct-list-initialization).
Last edited on
Topic archived. No new replies allowed.