This piece of code is dumb of course, but I only wrote it to illustrate the issue. Here it is:
#include <iostream>
using namespace std;
struct foo {
int a = 42;
template <typename T>
operator T* () {
cout << "operator T*()\n";
return reinterpret_cast<T*>(&a);
}
template <typename T>
operator const T* () const {
cout << "operator const T*() const\n";
return reinterpret_cast<const T*>(&a);
}
template <typename T>
T get() {
cout << "T get()\n";
return this->operator T();
}
};
int main() {
foo myFoo;
cout << *myFoo.get<const int*>() << '\n';
}
The output when compiled with Visual Studio 2019 (ISO C++17, /Ox) is:
T get()
operator const T*() const
42
The output with gcc 8.3 (-std=c++17, -O3) is:
T get()
operator T*()
42
So I'm wondering why the two compilers opt to call different const-qualified conversions given this code?
If I change get() to get() const, then both call the const version of the conversion. But isn't VS violating the standard by calling the const conversion from a method that isn't marked const?
EDIT:
To clear up some confusion around reinterpret_cast, here's a version without it which still produces the same output on both compilers.
The method:
template <typename T> foo::T get();
is not const.
That implies inside its body the object this is a pointer to foo type (and not const foo).
Therefore, the statement
this->operator T();
is going to call the no-const version because of the overload resolution.
As the standard states on [over.match.best], the version no-const is preferred because does not require any cast.
Indeed, in order to call the const version, the compiler should have implicitly cast into a const object (i.e. const_cast<const foo*>(this)).
Both gcc and clang follow what I have just said.
MSVC simply does not follow the standard here.
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