C++ Copy constructor gets called instead of initializer_list<> -


based on code

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);      // calls copy constructor again!     //shouldn't call initializer_list constructor?    foo c{b};        _getch();    return 0; } 

the output is:

default ctor

copy ctor

copy ctor

in third case, i'm putting b brace-initialization should call initializer_list<> constructor.

instead, copy constructor takes lead.

will of tell me how works , why?

as pointed out nicol bolas, original version of answer incorrect: cppreference @ time of writing incorrectly documented order in constructors considered in list-initialization. below answer using rules exist in n4140 draft of standard, close official c++14 standard.

the text of original answer still included, record.


updated answer

per nathanoliver's comment, gcc , clang produce different outputs in situation:

g++ -std=c++14 -wall -pedantic -pthread main.cpp && ./a.out default ctor copy ctor copy ctor initializer list   clang++ -std=c++14 -wall -pedantic -pthread main.cpp && ./a.out default ctor copy ctor copy ctor 

gcc correct.

n4140 [dcl.init.list]/1

list-initialization initialization of object or reference braced-init-list.

you're using list-initialization there, , since c object, rules list-initialization defined in [dcl.init.list]/3:

[dcl.init.list]/3:

list-initialization of object or reference of type t defined follows:

  1. if t aggregate...
  2. otherwise, if initializer list has no elements...
  3. otherwise, if t specialization of std::initializer_list<e>...

going through list far:

  1. foo not aggregate.
  2. it has 1 element.
  3. foo not specialization of std::initializer_list<e>.

then hit [dcl.init.list]/3.4:

otherwise, if t class type, constructors considered. applicable constructors enumerated , best 1 chosen through overload resolution (13.3, 13.3.1.7). if narrowing conversion (see below) required convert of arguments, program ill-formed.

now we're getting somewhere. 13.3.1.7 known [over.match.list]:

initialization list-initialization
when objects of non-aggregate class type t list-initialized (8.5.4), overload resolution selects constructor in 2 phases:

  1. initially, candidate functions initializer-list constructors (8.5.4) of class t , argument list consists of initializer list single argument.
  2. if no viable initializer-list constructor found, overload resolution performed again, candidate functions constructors of class t , argument list consists of elements of initializer list.

so copy constructor considered after initializer list constructors, in second phase of overload resolution. initializer list constructor should used here.

it's worth noting [over.match.list] continues with:

if initializer list has no elements , t has default constructor, first phase omitted. in copy-list initialization, if explicit constructor chosen, initialization ill-formed.

and after [dcl.init.list]/3.5 deals single-element list initialization:

otherwise, if initializer list has single element of type e , either t not reference type or referenced type reference-related e, object or reference initialized element; if narrowing conversion (see below) required convert element t, program ill-formed.

which explains cppreference got special case single-element list initialization, though placed higher in order should be.


original answer

you're encountering interesting aspect of list initialization, if list fulfills requirements may treated copy-initialization rather list-initialization.

from cppreference:

the effects of list initialization of object of type t are:

if t class type , initializer list has single element of same or derived type (possibly cv-qualified), object initialized element (by copy-initialization copy-list-initialization, or direct-initialization direct-list-initialization). (since c++14)

foo c{b} fulfills these requirements.


Comments

Popular posts from this blog

javascript - jQuery: Add class depending on URL in the best way -

caching - How to check if a url path exists in the service worker cache -

Redirect to a HTTPS version using .htaccess -