8
class Foo {
  public:
    Foo(float b) {}
};

class Bar {
  public:
    Bar(Foo foo) {}
};

int main(int argc, char *argv[]) {
    Bar b1(3.0f);  // accept, one implicit convertion happens there.
    Bar b2 = 3.0f;  // error: no viable conversion from 'float' to 'Bar'
    return 0;
}

Why does the second expression fail to compile? I expected that it would call the same converting constructor as same as the first expression.

Barry
  • 286,269
  • 29
  • 621
  • 977
Addict
  • 95
  • 6

2 Answers2

8

From [dcl.init]:

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 13.3.1.4, and the best one is chosen through overload resolution (13.3).

We can invoke a user-defined conversion that is from the source type directly to the target type. That is, if we had Bar(float ), we would consider that constructor. However, in this case, our candidate is simply Bar(Foo ), which does not take a float.

You are allowed zero or one user-defined conversion. In the direct-initialization case, we simply call Bar(Foo ) which invokes one user-defined conversion (float --> Foo). In the copy-initialization case, we are looking for a conversion sequence from float (the source type) all the way to Bar (the destination type), which would involve two user-defined conversions (float --> Foo, Foo --> Bar), hence the error.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • 1
    When the standard says "user-defined conversion sequences" what precisely counts. For instance the standard specifies things like narrowing conversions directly in the text of the standard. But what about things like conversions defined in the standard library? You don't normally say these are "user-defined" and I guess there are restrictions about what the user can do in namespace std. – Chris Beck Aug 17 '15 at 15:19
  • @ChrisBeck User-defined conversions are those conversions specified by either constructors (e.g. `Bar(Foo );`) or conversion functions (e.g. `operator Foo();`). – Barry Aug 17 '15 at 15:28
  • Barry: yeah I'm looking now in 12.3.1, it doesn't mention any different treatment for standard library so I guess those count as "user-defined" for these purposes – Chris Beck Aug 17 '15 at 15:28
  • 1
    @ChrisBeck You can also check out clause 4 - it enumerates all of the "standard conversions." – Barry Aug 17 '15 at 15:31
4

The second type of initialization is called copy-initialization and uses copy constructor. Therefore, this type of initialization expects the right side is convertible to Bar.

Eugene
  • 2,858
  • 1
  • 26
  • 25