Reputation: 14840
This code shows a basic wrapper class for the __int32
and bool
type. My intention is to extend basic types with methods and custom operators, etc.
Each class has one implicit constructor, allowing to assign an __int32
to an Int32
type implicitly. This works well, until there is a function overload accepting both Int32
or Boolean
.
While a function with the overloads __int32
and bool
compiles and works, the function with the classes as overloads results in Ambiguous calls to overloaded function.
My question: Is there a way to solve this properly, so I can implement wrapper classes for basic types without overload resolution problems and without the need for explicit casts by the caller?
class Boolean
{
private:
bool _Value = false;
public:
Boolean(bool value)
{
_Value = value;
}
};
class Int32
{
private:
__int32 _Value = 0;
public:
Int32(__int32 value)
{
_Value = value;
}
};
void AmbiguousFunc(const Int32 &x) { }
void AmbiguousFunc(const Boolean &x) { }
void NotAmbiguous(__int32 x) { }
void NotAmbiguous(bool x) { }
int main(int argc, char *argv[])
{
AmbiguousFunc(123); // Ambiguous calls to overloaded function
AmbiguousFunc((Int32)123); // works
NotAmbiguous(123);
return 0;
}
Upvotes: 1
Views: 96
Reputation: 172924
The problem is, given AmbiguousFunc(123);
, 123
could be converted to bool
(standard conversion), then converted to Boolean
(user-defined conversion); which has the same ranking with the user-defined conversion from 123
to Int32
, then the calling is ambiguous between AmbiguousFunc(const Int32 &)
and AmbiguousFunc(const Boolean &)
.
You can change the constructors as template, and restrict them to accept only appropriate types.
class Boolean
{
private:
bool _Value = false;
public:
// accept bools only; no __int32s
template <typename T, std::enable_if_t<std::is_same_v<T, bool>>* = nullptr>
Boolean(T value)
{
_Value = value;
}
};
class Int32
{
private:
__int32 _Value = 0;
public:
// accept __int32s only; no bools
template <typename T, std::enable_if_t<std::is_same_v<T, __int32>>* = nullptr>
Int32(T value)
{
_Value = value;
}
};
Upvotes: 3