1
struct X {
      X() {}
      X(X&&) { }
};
X global_m;

struct Converts {
        operator X&& () const { return std::move(global_m); }
};

I believe the following should work:

X x { Converts{} };

There is only one single-argument constructor for X. It takes an X&&. The Converts object is temporary, and it converts to X&&. So why do I get this error message from clang-3.3:

 // error: "candidate constructor not viable: no known conversion from 'Converts' to 'X &&' for 1st argument"

I'm able to explicitly call the operator as:

X x { Converts{}.operator struct X&& () }; // this works.

Unfortunately for me, it works on ideone, which is based on g++ as far as I know. Is there any online clang compiler that's up and running at the moment?

Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • I've found clang 3.0 online and it compiled my code (after I made a few, unrelated, changes to support the old code. Maybe this is just some specific to clang 3.3. I'm finding it hard to replicate this compilation error online! Maybe it's a bug in 3.3? Anybody else able to replicate this? – Aaron McDaid Nov 02 '13 at 19:16
  • It's not a bug read this [answer](http://stackoverflow.com/questions/19737929/why-does-bool-b-2-work-well-but-bool-b-2-yield-a-warning-of-narrowing/19737945#19737945) , basically if you have a narrowing in an initialization list it's an illformed program and the compiler must either stop or issue a diagnostic – aaronman Nov 02 '13 at 19:21
  • Ah! @aaronman, I've now changed the `{` and `}` to `(` and `)` and it worked. I'm gonna need to be more careful about `{`. Thanks for suggesting that might be (part of?) the problem. – Aaron McDaid Nov 02 '13 at 19:25
  • @aaronman I fail to understand why this is narrowing. Here, there are only two user-defined and no fundamental types involved. – dyp Nov 02 '13 at 19:27
  • 2
    Ok I think this might actually be a better match to your question, [here](http://stackoverflow.com/questions/12677711/is-it-possible-to-invoke-a-user-defined-conversion-function-via-list-initializat) seems like accepting the code is a bug that has been fixed – aaronman Nov 02 '13 at 19:35
  • Thanks, @aaronman. I'll accept if you post that as an answer. – Aaron McDaid Nov 03 '13 at 14:15
  • @AaronMcDaid posted it, have to be honest though didn't fully understand the bug – aaronman Nov 03 '13 at 22:48
  • This is actually a duplicate of the question @aaronman found. – Ben Voigt Nov 03 '13 at 23:13
  • @BenVoigt I know, I figured I'd post an answer since he asked me though – aaronman Nov 03 '13 at 23:21
  • I've also voted to close as dupe. **But**, I think I like the title on my question. Other people, who are mystified at the failure to convert, would never think of list-initialization and might never discover the other question and the other answer. (I guess that's why duped questions aren't deleted.) Duplicate answer, not entirely duplicate question perhaps? :-) – Aaron McDaid Nov 04 '13 at 01:13
  • @AaronMcDaid: Yes, I think that's one of the reasons that duplicate questions aren't deleted... each is a new set of keywords and search terms to help find the useful content. – Ben Voigt Nov 04 '13 at 23:08

1 Answers1

1

According to this answer it was a defect in the standard. This is the correction to the standard @ecatmur proposed.

4 - However, when considering the argument of a constructor or user-defined conversion function that is a candidate:

  • by 13.3.1.3 [over.match.ctor] when invoked for the copying of the temporary in the second step of a class copy-initialization, or
  • by 13.3.1.4 [over.match.copy], 13.3.1.5 [over.match.conv], or 13.3.1.6 [over.match.ref] in all cases,

only standard conversion sequences and ellipsis conversion sequences are considered; when considering the first argument of a constructor of a class X that is a candidate by 13.3.1.7 [over.match.list] when passing the initializer list as a single argument or when the initializer list has exactly one element, a user-defined conversion to X or reference to (possibly cv-qualified) X is only considered if its user-defined conversion is specified by a conversion function. [Note: because more than one user-defined conversion is allowed in an implicit conversion sequence in the context of list-initialization, this restriction is necessary to ensure that a converting constructor of X, called with a single argument a that is not of type X or a type derived from X, is not ambiguous against a constructor of X called with a temporary X object itself constructed from a. -- end note]

I don't know if this is exactly how the standard ended up being changed (since I only have a draft) but I would assume something was done because of the change in results depending on the compiler version

Community
  • 1
  • 1
aaronman
  • 18,343
  • 7
  • 63
  • 78