3

So I have this code:

struct Foo {
    Foo() { cout << "default\n"; }
    Foo(const long long) { cout << "implicit\n"; }
};

struct Bar {
    Bar(const short param) : param(param) {}
    operator long long() const { return static_cast<long long>(param); }
    const short param;
};

I would have thought that Foo foo = Bar(13) would have used my implicit cast and then the converting constructor. But it errors:

error: conversion from Bar to non-scalar type Foo requested

This works fine though: Foo foo(Bar(13)). Why is my implicit cast used for explicit converting construction, but not for implicit converting construction?

The rules I got from https://en.cppreference.com/w/cpp/language/copy_initialization say:

The result of the conversion, which is a prvalue expression if a converting constructor was used, is then used to direct-initialize the object

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288

2 Answers2

8

Firstly the implicit conversion from Bar to long long, and the one from long long to Foo are both user-defined conversion.

Foo foo = Bar(13); perform copy initialization, the compiler will try to convert Bar to Foo implicitly. Two implicit conversions are required, i.e. converting Bar to long long and then converting long long to Foo. But only one user-defined conversion is allowed in one implicit conversion sequence.

Implicit conversion sequence consists of the following, in this order:

1) zero or one standard conversion sequence;

2) zero or one user-defined conversion;

3) zero or one standard conversion sequence.

A user-defined conversion consists of zero or one non-explicit single-argument constructor or non-explicit conversion function call

Foo foo(Bar(13)); performs direct initialization. The constructors of Foo would be examined and the best match is selected by overload resolution. Only one implicit user-defined conversion (from Bar to long long) is required; after that Foo::Foo(long long) is called to construct foo directly.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
  • So more conversions are allowed in explicit conversion? Cause that has to do 2 conversions (if we're considering the converting constructor a conversion.) – Jonathan Mee May 18 '18 at 15:40
  • @JonathanMee *So more conversions are allowed in explicit conversion* Sure, you can specify as many casts as you want if you do it explicitly. – NathanOliver May 18 '18 at 15:42
  • 2
    There is only one implicit conversion in `Foo foo(Bar(13))`, from `Bar` to `long long`. But `Foo foo = Bar(13)` requires the `Bar` be converted to `long long` and then to `Foo` so that `foo` can be copy-constructed. – Miles Budnek May 18 '18 at 15:44
  • @JonathanMee Answer revised. – songyuanyao May 18 '18 at 15:46
2

As you use copy initialization then according to documentation

In addition, the implicit conversion in copy-initialization must produce T directly from the initializer, while, e.g. direct-initialization expects an implicit conversion from the initializer to an argument of T's constructor.

emphasis is mine. This is not the case.

Slava
  • 43,454
  • 1
  • 47
  • 90