3

In my Qt5 project, I encountered the following setup:

#include <initializer_list>

struct QJsonArray;

struct QJsonValue
{
    /*explicit*/ QJsonValue(QJsonArray const &) {}
};

struct QJsonArray
{
    QJsonArray(QJsonArray const &) {}
    QJsonArray(std::initializer_list<QJsonValue>) {}
};

void f(QJsonArray a = {})
{
    QJsonArray b {a}; // GCC: init-list ; Clang: Copy-Cc
    QJsonArray c (a); // GCC: Copy-Cc   ; Clang: Copy-Cc
}

int main()
{
    f();
}

You can see that on the commented lines that GCC and Clang disagree on what constructor should be called.

(You can test this code on C++ Compiler Explorer with latest GCC and Clang with flag -std=c++11)

If I uncomment the explicit, both compilers select the same constructor (the copy constructor).

Which compiler is right here?

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Chnossos
  • 9,971
  • 4
  • 28
  • 40

1 Answers1

4

GCC is correct here. For non-aggregates, using braced-init-lists can bypass copy constructors, preferring a matching initializer_list constructor. Since QJsonArray can be implicitly converted into a QJsonValue, and QJsonArray has an initializer_list constructor that takes QJsonValues, that constructor will be preferred, even over the copy constructor.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982