Consider the following setup:
struct MyInt {
template<class T>
operator T() = delete;
operator int(){ return 42; }
};
struct TestCArr {
int arr[2];
};
struct TestStdArr {
std::array<int, 2> arr;
};
MyInt
here is implicitly convertible to int
, but all other conversions are deleted.
The following compiles as expected with all major compilers using aggreagate initialization to initialize arr[0]
with MyInt{}
via operator int()
:
TestCArr{ MyInt{} };
But what is the expected behavior of the following statement?
TestStdArr{ MyInt{} };
To my understanding, this should not compile:
MyInt
has a conversion operator to std::array<int, 2>
, so that should be the best fit. But that operator is deleted, so I'd expect a compile time error. (The difference to before is that it is impossible to have a conversion operator to int[2]
, so the conversion to int
is used.)
MSVC and gcc seem to agree with me, but clang compiles the statement, picking the conversion operator to int
and aggregate initializes the first member of arr
(see https://godbolt.org/z/dK4ronrGv).
So is my understanding correct that operator std::array<int, 2>()
is a better fit than operator int()
and therefore has a higher priority, even though it is deleted?
P.S. If I remove the deleted operator T()
from MyInt
, the above statement compiles with all three major compilers, all choosing operator int()
to perform aggregate initialization: https://godbolt.org/z/sYr7ff793
P.P.S If I use the following definition of MyInt
, the behavior of all compilers stays the same (removing arguments concerning templates vs non-templates and more constrained vs less constrained): https://godbolt.org/z/cvhMj9xPq
struct MyInt {
template<class T>
requires (!std::integral<T>)
operator T() = delete;
template<class T>
requires std::integral<T>
operator T() { return 42; };
};