I am working with some legacy code, where one of the previous developers created a Guid (Global Unique IDentifier) class that used Microsoft’s GUID struct as a member variable (member "MS" below). To allow easy conversion between the two, the following two conversion/casting operators were defined in Guid.h:
/// Returns a GUID structure
operator GUID() const
{
return MS;
}
/// Returns a reference to a GUID structure
operator GUID&()
{
return MS;
}
On moving the codebase to a VS2019 build, I get the following compiler error:
error C2593: 'operator =' is ambiguous C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\guiddef.h(27): note: could be '_GUID &_GUID::operator =(_GUID &&)' C:\Program Files (x86)\Windows Kits\10\include\10.0.18362.0\shared\guiddef.h(27): note: or
'_GUID &_GUID::operator =(const _GUID &)'
I’m assuming either the compiler has become more strict (since VS2013) or Microsoft updated their GUID definition with a second overloaded GUID assignment operator. An example of where this error is hit is as follows:
void GuidExample(Guid initial)
{
GUID myGUID = initial;
}
My understanding is that during the assignment, the compiler will try to convert the Guid to a GUID using one of the two conversion operators we’ve supplied. However, it doesn’t know which one of our conversion operators to use, and therefore doesn’t know which assignment operator to use.
If I comment out either of the two conversion operators, I don’t get any compiler errors. Return by reference will allow access to GUID MS, which is OK because it is a public member anyway. So If I have to go with one definition of the conversion operation, I will go with the reference version.
However my question is, is there a way to keep both definitions and avoid the ambiguity?
UPDATE: Minimum reproducible example. This will build in VS2013 and will not in VS2019, showing the "'operator =' is ambiguous" error I noted earlier.
#include <guiddef.h>
class Guid
{
public:
union
{
char Data[16];
GUID MS;
struct
{
int Q1;
int Q2;
};
};
Guid()
{
Q1 = 0;
Q2 = 0;
}
/// Returns a GUID structure
operator GUID() const
{
return MS;
}
/// Returns a reference to a GUID structure
operator GUID& ()
{
return MS;
}
};
GUID winGUID;
void testAssign(Guid myGuid)
{
winGUID = myGuid; //This causes ambiguity
GUID anotherWinGUID = myGuid; //This does not
}
int main()
{
Guid a;
testAssign(a);
return 0;
}
The error tells you that the compiler cannot choose between copy-assignment and move-assignment. So you're right, there are now two overloads of the assignment operator, and they're just the usual ones.
The compiler might be more strict. Visual C++ has been tightening the rules with
/permissive-
, starting with VS2015 Update 3.The fix is probably straightforward:
The idea here is that you don't want a
GUID&
reference to a temporaryGuid
object which might not even survive after the call tooperator GUID&()
.