简体   繁体   中英

Why the following code with non-const conversion function is not ambiguous?

Consider the following code (taken from https://en.cppreference.com/w/cpp/language/cast_operator )

struct To {
    To() = default;
    To(const struct From&) {} // converting constructor
};

struct From {
    operator To() const {return To();} // conversion function
};

int main()
{
    From f;

    To t2 = f; // copy-initialization: ambiguous
// (note, if conversion function is from a non-const type, e.g.
//  From::operator To();, it will be selected instead of the ctor in this case)
}

As the comments say, the following line is indeed ambiguous because there are two candidates (The conversion function and the converting constructor are equally applicable)

To t2 = f; //compile error

However, as the note says if I remove the const from the conversion function resulting in the following code:

struct From {
    operator To() {return To();} // conversion function
};

The call compiles fine.
The const qualifier should not affect the conversion function return value, so why the call is no longer ambiguous?

The const qualifier should not affect the conversion function return value, so why the call is no longer ambiguous?

It does not affect the result, but it affects overload resolution for choosing the best viable method. It's similar to the case of these made up functions

To make(From const&);
To make(From&);

Which overload is the better match in make(f) ? It's the second one, because the parameter type, being non-const, better matches the argument ( f ), which is non-const itself.

The const qualifier should not affect the conversion function return value

It doesn't affect that indeed, but that's also not relevant.

What it does affect is the argument - which is the implicit reference to this . The implicit argument is a const lvalue for const member functions and non-const for non-const member functions. The arguments are what affect the overload resolution.

In the original code, both the constructor and the conversion operator arguments are exactly the same, so a conversion sequence from any type to either argument is equally preferable, and therefore ambiguous.

Without the const, your non-const lvalue expression f doesn't need any conversions, while the constructor does require a conversion into const lvalue. As such, the operator is preferred by the overload resolution. If you had written const From f; , then the constructor whose argument is const would have been chosen instead as in that case, the non-const conversion operator wouldn't even be valid candidate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM