I was playing around with the new "deducing this" functionality in C++23, and found a case that gcc and clang disagree on, and I was hoping to get a ruling on which compiler is correct. I've minimized the original code I was working on into the following example. Consider the following case:
#include <utility>
#include <type_traits>
struct foo {
int asdf;
template <class T, class O>
using conversion_type = std::conditional_t<
std::is_lvalue_reference_v<O>,
T&,
T
>;
template <class Self>
operator conversion_type<int, Self>(this Self&& self) {
return std::forward<Self>(self).asdf;
}
};
int main() {
foo f;
int& fdsa = f;
int&& asdf = std::move(f);
}
Without worrying too much about why on Earth I was doing this, I was trying to declare an implicit conversion operator that changes the value category of the type it converts TO based on the deduced value category of the object being converted FROM.
In this particular case, if the object to be converted is an lvalue, I'd like the conversion operator to resolve to converting to an lvalue reference to the subobject, and if not, I'd like it to resolve to converting to a temporary (not an rvalue reference, I'd like it to instead move the subobject into a new temporary).
gcc is entirely willing to compile this code, and it appears to work as I was expecting. clang will compile the third line inside of main, but will not compile the second, claiming that non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'foo'
, which sounds to me like it's not even considering the conversion operator.
Given the fact that clang appears to be inconsistent in its handling of this, I assume this is likely a clang bug, but I wanted to see what the general wisdom was.
Here's a link to compiler explorer that demonstrates the issue: https://godbolt.org/z/dG6jTj9rr
If you switch the compiler to any version of gcc 14, it will build without issues. Any ideas?
The program is well-formed and clang and msvc are wrong to give a diagnostic for int& fdsa = f;
.
In particular, you're using a forwarding reference which means when you wrote int &fdsa = f;
, the parameter Self
will be deduced as foo&
which is an non-const lvalue reference. This in turn means that conversion_type<int, Self>
will be int&
.
And a call to a function returning an lvalue refernce is considered to be an lvalue and we're allowed to bind the result to an non-const lvalue ref fdsa
.
Here is the confirmed clang bug:
Clang rejects valid program involving conversion function with lvalue ref return type
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With