[Bug c++/66392] New: rejects-valid: copy-initialization through user-defined conversion sequence fails

filip.roseen at gmail dot com gcc-bugzilla@gcc.gnu.org
Wed Jun 3 08:24:00 GMT 2015


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66392

            Bug ID: 66392
           Summary: rejects-valid: copy-initialization through
                    user-defined conversion sequence fails
           Product: gcc
           Version: 5.1.0
            Status: UNCONFIRMED
          Keywords: rejects-valid
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: filip.roseen at gmail dot com
  Target Milestone: ---

Created attachment 35687
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=35687&action=edit
testcase.cpp - inaccurately rejected

There are many variants of the supplied testcase, but the following shall
compile due to the wording of `[dcl.init]p17` (and relevant sections) - `gcc`
inaccurately rejects the snippet:

    struct B { };

    struct A { 
      explicit A (A const&);
               A (B const&);
    };  

    int main () {
      A x = B {}; // legal
    }   

---------------

    testcase.cpp: In function ‘int main()’:
    testcase.cpp:9:12: error: no matching function for call to ‘A::A(A)’
       A x = B {}; // legal
                ^
    testcase.cpp:5:12: note: candidate: A::A(const B&)
                A (B const&);
                ^
    testcase.cpp:5:12: note:   no known conversion for argument 1 from ‘A’ to
‘const B&’
    testcase.cpp:5:12: note:   after user-defined conversion: A::A(const B&)

---------------

[ Note: `msvc`, `clang`, `icc` all accept the above snippet ]

---------------

In short the ISO C++ Standard says that if copy-initialization takes place
where the source type is not the same as the destination type, but there is a
user-defined conversion sequence that can convert the source type into the
destination type - such will be used to construct a temporary, and that
temporary will then be used to _direct-initialize_ the destination object.

It should be noted, as directly addressed in the standard wording, that
copy-elision may be used to skip the construction of the temporary object.

[ Note: it is important to note that the wording talks about "user-defined
conversion sequences", as such one must properly take into account usage of
`operator T`, where `T` is the destination type, in the source type which shall
yield the same described behavior as the attached testcase ]

------------------------------------------

Relevant part of `[dcl.init]p17`:

> Otherwise (i.e., for the remaining copy-initialization cases), user-defined
> conversion sequences that can convert from the source type to the destination
> type or (when a conversion function is used) to a derived class thereof are
> enumerated as described in [over.match.copy], and the best one is chosen through
> overload resolution ([over.match]). If the conversion cannot be done or is
> ambiguous, the initialization is ill-formed. The function selected is called
> with the initializer expression as its argument; if the function is a
> constructor, the call initializes a temporary of the cv-unqualified version of
> the destination type. The temporary is a prvalue. The result of the call (which
> is the temporary for the constructor case) is then used to direct-initialize,
> according to the rules above, the object that is the destination of the
> copy-initialization. In certain cases, an implementation is permitted to
> eliminate the copying inherent in this direct-initialization by constructing the
> intermediate result directly into the object being initialized; see
> [class.temporary], [class.copy]


More information about the Gcc-bugs mailing list