Jonathan Mee
Jonathan Mee

Reputation: 38919

Why Doesn't This Do an Implicit Cast to the Converting Constructor?

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

Upvotes: 3

Views: 209

Answers (2)

songyuanyao
songyuanyao

Reputation: 172884

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.

Upvotes: 8

Slava
Slava

Reputation: 44238

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.

Upvotes: 2

Related Questions