initializer-list overload issue

== Summary ==

In clang 3.7, overload resolution between an initializer-list constructor and a copy constructor favors the copy constructor. The standard seems to specify that explicit initializer-list constructors take precedence in overload resolution. This behavior is different from clang 3.6 and from all versions of gcc. This behavior is not observed when the overload resolution is between an initializer-list constructor and a non-copy constructor.

This was encountered when converting a recursive tree-like type from gcc to clang. The tree-like type could accept an initializer-list of children, but passing a single child would invoke the copy constructor instead.

== Minimal code example: ==

#include <initializer_list>
struct T {
int x;
T() : x(0) {}
T(const T&) : x(1) {}
T(std::initializer_list) : x(2) {}
};
int foo() {
T t1;
T t2 = { t1 };
return t2.x;
}

In clang 3.7, foo() returns 1. In clang 3.6 and all versions of gcc, foo() returns 2.
The overload resolution in clang 3.7 is consistent with clang 3.6 and gcc when a non-copy constructor is involved; the following example returns 4 on all tested compilers.

#include <initializer_list>
struct T {
int x;
T(int) : x(3) {}
T(std::initializer_list) : x(4) {}
};
int foo() {
T t = { 7 };
return t.x;
}

== Standard references (n3936): ==

  • 8.5.4 “List-initialization”
  • 13.3.1.7, “Initialization by list-initialization”

Regards,
Nicholas