I got a bit confused about initialization of constant references using {}
.
So here's my code:
#include <iostream>
#include <initializer_list>
template <typename T>
class Test
{
public:
Test(std::initializer_list<T> l)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test(const Test<T>& copy)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Test() = delete;
};
int main()
{
Test<int> t1 {100500};
//here temporary constructed with copy constructor
//ref1 bound to temporary
const auto& ref1 = {t1};
//no temporary, ref2 bound to t1
const Test<int>& ref2 = {t1};
//temporary constructed with copy constructor
//ref3 bound to temporary
const Test<int>& ref3 = {{t1}};
return 0;
}
The source of my confusion is different behaviour of these 3 initializations. Looks like they do different things and follow different rules. Could someone clarify what exactly happens in each case?
My OS:
Linux Mint 19 Tara
Compiler:
gcc 7.3.0
Compilation command:
g++ -std=c++11 -O0 test.cpp -o test -Wall -pedantic
For const auto& ref1 = {t1}
Copy list initialization is performed, the deduced type for ref1
is std::initializer_list<Test<int>>
and in the process copy initialization is done for it elements, Test<int>
copy constructor is called.
Note: the comment you have inside ref1
might mislead you, the temporary bound to ref1
is not of type Test<int>
is of type std::initializer_list<Test<int>>
.
const Test<int>& ref2 = {t1}
This is in the context of copy list initialization there's a special rule for reference binding initialized with braces with one element, the reference bind directly, no temporary introduced.
const Test<int>& ref3 = {{t1}}
In this case the reference don't bind directly, {t1}
needs to be converted into a type to bind the reference, {t1}
copy initialize a temporary(Test<int>
copy constructor called) and that temporary is used to initialize ref3
.