c++ - Calling an explicit constructor with a braced-init list: ambiguous or not? -


consider following:

struct {     a(int, int) { } };  struct b {     b(a ) { }                   // (1)     explicit b(int, int ) { }   // (2) };  int main() {     b paren({1, 2});   // (3)     b brace{1, 2};     // (4) } 

the construction of brace in (4) , unambiguously calls (2). on clang, construction of paren in (3) unambiguously calls (1) on gcc 5.2, fails compile with:

main.cpp: in function 'int main()': main.cpp:11:19: error: call of overloaded 'b(<brace-enclosed initializer list>)' ambiguous      b paren({1, 2});                    ^ main.cpp:6:5: note: candidate: b::b(a)      b(a ) { }        ^ main.cpp:5:8: note: candidate: constexpr b::b(const b&)  struct b {         ^ main.cpp:5:8: note: candidate: constexpr b::b(b&&) 

which compiler right? suspect clang correct here, ambiguity in gcc can arise through path involves implicitly constructing b{1,2} , passing copy/move constructor - yet constructor marked explicit, such implicit construction should not allowed.

as far can tell, this clang bug.

copy-list-initialization has rather unintuitive behaviour: considers explicit constructors viable until overload resolution finished, can reject overload result if explicit constructor chosen. wording in post-n4567 draft, [over.match.list]p1

in copy-list-initialization, if explicit constructor chosen, initialization ill-formed. [ note: differs other situations (13.3.1.3, 13.3.1.4), converting constructors considered copy-initialization. restriction applies if initialization part of final result of overload resolution. — end note ]


clang head accepts following program:

#include <iostream> using namespace std;  struct string1 {     explicit string1(const char*) { cout << "string1\n"; } }; struct string2 {     string2(const char*) { cout << "string2\n"; } };  void f1(string1) { cout << "f1(string1)\n"; } void f2(string2) { cout << "f2(string2)\n"; } void f(string1) { cout << "f(string1)\n"; } void f(string2) { cout << "f(string2)\n"; }  int main() {     //f1( {"asdf"} );     f2( {"asdf"} );     f( {"asdf"} ); } 

which is, except commenting out call f1, straight bjarne stroustrup's n2532 - uniform initialization, chapter 4. johannes schaub showing me paper on std-discussion.

the same chapter contains following explanation:

the real advantage of explicit renders f1("asdf") error. problem overload resolution “prefers” non-explicit constructors, f("asdf") calls f(string2). consider resolution of f("asdf") less ideal because writer of string2 didn’t mean resolve ambiguities in favor of string2 (at least not in every case explicit , non-explicit constructors occur this) , writer of string1 didn’t. rule favors “sloppy programmers” don’t use explicit.


for know, n2640 - initializer lists — alternative mechanism , rationale last paper includes rationale kind of overload resolution; successor n2672 voted c++11 draft.

from chapter "the meaning of explicit":

a first approach make example ill-formed require constructors (explicit , non-explicit) considered implicit conversions, if explicit constructor ends being selected, program ill-formed. rule may introduce own surprises; example:

struct matrix {     explicit matrix(int n, int n); }; matrix transpose(matrix);  struct pixel {     pixel(int row, int col); }; pixel transpose(pixel);  pixel p = transpose({x, y}); // error. 

a second approach ignore explicit constructors when looking viability of implicit conversion, include them when selecting converting constructor: if explicit constructor ends being selected, program ill-formed. alternative approach allows last (pixel-vs-matrix) example work expected (transpose(pixel) selected), while making original example ("x x4 = { 10 };") ill-formed.

while paper proposes use second approach, wording seems flawed - in interpretation of wording, doesn't produce behaviour outlined in rationale part of paper. wording revised in n2672 use first approach, couldn't find discussion why changed.


there of course more wording involved in initializing variable in op, considering difference in behaviour between clang , gcc same first sample program in answer, think covers main points.


Comments

Popular posts from this blog

how to insert data php javascript mysql with multiple array session 2 -

multithreading - Exception in Application constructor -

windows - CertCreateCertificateContext returns CRYPT_E_ASN1_BADTAG / 8009310b -