Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ constructor taking an std::initializer_list of size one

The idea behind the below example program code is to illustrate the fact that having an initializer list constructor that is not equivalent to the default copy constructor when given exactly one element can lead to somehow unexpected results with Clang.

It also shows that Clang and GCC do not implement the same precedence between the copy constructor and the initializer list constructor which in practice makes the use of such kind of initializer list constructor impossible for portable code.

// Include directive.
#include <initializer_list>

// The struct used in this case.
struct Foo
{
  // Member value.
  int val;

  // Default constructor.
  Foo() : val(0) {}

  // Initializer list constructor.
  Foo(std::initializer_list<Foo>) : val(2) {}
};


// Main function.
int main()
{
  // Default constructed Foo object.
  Foo foo_zero;

  // It is not clear to me which constructor
  // should be called by the following statement.
  Foo foo_test = { foo_zero };

  // Return exit code.
  // Clang 6.0.0 returns 0 (i.e. implicit copy constructor was called for 'foo_test').
  // GCC 8.2 returns 2 (i.e. initializer list constructor was called for 'foo_test').
  return foo_test.val;
}

My questions are the following:

  1. What should be the return value of my example program (Clang and GCC do not seem to agree)?

  2. Is there a way to have the initializer list constructor of my example program called with the syntax used that works with Clang and GCC?

like image 365
Ankur deDev Avatar asked Oct 16 '22 14:10

Ankur deDev


1 Answers

Clang implemented DR 1467 (brace-initializing a T from a T behaves as if you didn't use braces) but has yet to implement DR 2137 (on second thought, do that only for aggregates).

Your code should return 2.

A possible workaround is Foo foo_test({ foo_zero });.

like image 188
T.C. Avatar answered Nov 02 '22 23:11

T.C.