5

The following code works fine:

#include <iostream>

struct B
{
    operator int()
    {
        return int();
    }
};

struct A
{
    A(int, int){ std::cout << "A(int, int)" << std::endl; }
};

A a({B(), B()});

int main()
{ 
}

and produces output:

A(int, int)

DEMO

But I can't get why? What the Standard says is:

However, when considering the argument of a constructor or user-defined conversion function that is a candidate by 13.3.1.3 when invoked for the copying/moving of the temporary in the second step of a class copy-initialization, by 13.3.1.7 when passing the initializer list as a single argument or when the initializer list has exactly one element and a conversion to some class X or reference to (possibly cv-qualified) X is considered for the first parameter of a constructor of X [...] only standard conversion sequences and ellipsis conversion sequences are considered

So in our case we considered the argument of the constructor (it was {B(), B()}). More precisely, we passed initializer-list as a single argument (the second case in the rule I cited). Now, we need to convert the first element of the initializer-list (temporary of type B) to int and the only way to do that is to apply user-defined convertion (B::operator int()). But, as said at the end of rule that I cited only standard conversion sequences and ellipsis conversion sequences was considered. Since, that code shouldn't work, it should throw the error like A(int, int) is not viable or sort of.

What's wrong. May be it's a bug?

Columbo
  • 60,038
  • 8
  • 155
  • 203
  • Cannot find this quote in N4140. What draft and paragraph are you quoting? – Columbo Dec 01 '14 at 17:19
  • @Columbo: C++11 13.3.3.1/4 – Mike Seymour Dec 01 '14 at 17:32
  • possible duplicate of [Distinguishing between user-defined conversion sequences by the initial standard conversion sequence](http://stackoverflow.com/questions/11555950/distinguishing-between-user-defined-conversion-sequences-by-the-initial-standard) – Jonathan Mee Dec 01 '14 at 17:33

1 Answers1

1

The wording was defective and changed with C++14. Now [over.best.ics]/4 reads

However, if the target is

  • the first parameter of a constructor or
  • […]

and the constructor or user-defined conversion function is a candidate by

  • 13.3.1.3, when the argument is the temporary in the second step of a class copy-initialization,
  • 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), or
  • the second phase of 13.3.1.7 when the initializer list has exactly one element, and the target is the first parameter of a constructor of class X, and the conversion is to X or reference to (possibly cv-qualified) X,

user-defined conversion sequences are not considered. [ Note: These rules prevent more than one user-defined conversion from being applied during overload resolution, thereby avoiding infinite recursion. — end note ]

The conversion of B() to int is not covered by this - the bold phrase only appertains to the binding of a reference to a temporary during copy-initialization.
However, Clang rejects this sample code according to the above:

class A;

struct B
{
    operator A();
};

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

A a{B()};
Columbo
  • 60,038
  • 8
  • 155
  • 203