1

I happen to come across this, and I don't get it, why Foo c{a} called the 2 constructors. I know that every time an object is created, the constructor, is called, so why does it called the foo(std::initializer_list<Foo>) even if he did not do this Foo c{{a}} or Foo c({a})?

struct Foo {
    Foo() {}

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

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

int main() {
    Foo a;
    Foo b(a); // copy ctor
    Foo c{a}; // copy ctor (init. list element) + initializer list!!!
}
0_NULL
  • 73
  • 1
  • 7
  • Because the list initialization constructor has precedence in that case, as defined by the standard – JHBonarius Nov 23 '20 at 09:42
  • 2
    Let me cite [cppreference](https://en.cppreference.com/w/cpp/utility/initializer_list): _The underlying array is a temporary array of type `const T[N]`, in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list._ – Evg Nov 23 '20 at 09:42
  • from the answer "you should be aware that the initializer_list<> constructor is preferred to the other constructors" does this not answer your question? (serious question, really not sure if that is sufficient to clarify your doubts) – 463035818_is_not_an_ai Nov 23 '20 at 09:43
  • I mean, why can he call 2 constructors? should be it only one? – 0_NULL Nov 23 '20 at 09:45
  • initializer list constructors are different. There are special rules for them. You won't understand how it works by just considering `std::initializer_list` as a type like others – 463035818_is_not_an_ai Nov 23 '20 at 09:46
  • 2
    GCC and Clang [disagree](https://godbolt.org/z/7h154a) with each other. – Evg Nov 23 '20 at 09:47
  • @Evg bug in clang, or am I missing something that makes both valid outcomes? – 463035818_is_not_an_ai Nov 23 '20 at 09:54
  • @Evg, I got more confused, why is that? if the `std::initializer_list` is more preferred, then why did Clang outputted, the non-initializer_list constructor? is it differ from compiler to compiler? – 0_NULL Nov 23 '20 at 09:58
  • @RenzAguirre, the second constructor is understandable: internally, `initializer_list` holds const objects, to construct those objects (here, just one object) a copy constructor invocation is needed. Why GCC and Clang differ and which compiler is right (or both) I'm not ready to say now. – Evg Nov 23 '20 at 10:49
  • 2
    Different compilers have different bugs. This one is a clang bug. – n. m. could be an AI Nov 23 '20 at 22:05

1 Answers1

0

If we look at https://en.cppreference.com/w/cpp/language/direct_initialization

Here we see:

T object { arg }; (2) (since C++11)

  1. initialization of an object of non-class type with a single brace-enclosed initializer (note: for class types and other uses of braced-init-list, see list-initialization)

In https://en.cppreference.com/w/cpp/language/list_initialization there is following bullet:

If T is an aggregate class 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 copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization). (since C++14)

And returning to direct initialization:

the constructors of T are examined and the best match is selected by overload resolution. The constructor is then called to initialize the object.

So, it seems that in this situation clang is right to call copy constructor and GCC is wrong. At least since C++14.

sklott
  • 2,634
  • 6
  • 17
  • Foo is not an aggregate. – n. m. could be an AI Nov 23 '20 at 21:59
  • 1
    It is actually a long-standing [clang bug](https://bugs.llvm.org/show_bug.cgi?id=23812). – n. m. could be an AI Nov 23 '20 at 22:03
  • @n.'pronouns'm. Sorry but I'm really having a hard time understanding it. If that's the case, I still don't understand how and why did `Foo c{a}` called two constructor, should it be only one, making clang output right? because its more intuitive in my mind. more specifically, if the precedence of the `std::initializer_list` constructor is higher, should it only called that constructor? do you maybe have examples for me to better understand it? – 0_NULL Nov 24 '20 at 03:14
  • @RenzAguirre How do you pass an argument to that constructor? – n. m. could be an AI Nov 24 '20 at 05:17
  • @n.'pronouns'm. either `Foo({n}}` or `Foo({n})` is this right? – 0_NULL Nov 24 '20 at 05:42
  • @RenzAguirre Um, no. You pass an argument **by copy**. Passing an argument to any function by copy involves a copy constructor. – n. m. could be an AI Nov 24 '20 at 05:45