In brief
When I learned about C++ initialization these days, I found To to = from; behaves differently from To to = {from};, where from is of another type From:
If conversion constructor To::To(From &) and conversion operator From::operator To() are provided, both of them will be considered for To to = from;, which will cause a compile error. However, only the conversion constructor will be considered for To to = {from};, which will work fine. What the hack here?
To be detailed
Code to reproduce this case on GCC 10.3 with C++20 applied:
class From;
class To {
public:
To() = default;
To(From &) {std::cout << "conversion constructor\n";}
};
class From {
public:
operator To() {std::cout << "conversion operator\n"; return {};}
};
int main(int argc, char **argv) {
From from;
// To to1 = from;
To to2 = {from};
return 0;
}
Uncomment the line and we'll get the error:
case.cpp: In function ‘int main(int, char**)’:
case.cpp:17:14: error: conversion from ‘From’ to ‘To’ is ambiguous
17 | To to1 = from;
| ^~~~
From what I can tell, To to = from; is copy initialization. And this page says "the conversion functions and constructors are both considered by overload resolution in copy-initialization", which is pretty much about the error.
What about To to = {from}; then? It is listed as an old way of copy initialization. But it's up untill C++11 and is probably not the case. Is it list initialization? Can someone give an explanation of how it deals with conversion constructor and conversion operator?
Additional discussion
I also experimented with C++11 in-class initialization, with a few more lines of code:
class InClsInitialization {
private:
From from;
// To to1 = from;
To to2 = {from};
};
The result seems to be the same (i.e., uncomment the line and we'll get the same error), though I don't find which category of initialization it belongs to.
To to = from;is copy-initialization. It falls under [dcl.init.general]/16.6.3, according to whichBoth converting constructors of
Toand conversion functions ofFromare considered. (Since this is copy-initialization,explicitfunctions will be ignored.)To to = {from};is copy-list-initialization. Copy-list-initialization is a type of copy-initialization, but has different rules. SinceTois not an aggregate, it falls under [dcl.init.list]/3.7, according to whichThus, conversion functions are not considered. (Explicit constructors are considered, but the program is ill-formed if one of them is chosen by overload resolution.)