In this case I would also recommend an explicit
constructor, because I think that an arbitrary string (which your constructor takes) does not model a number (which your CBigInt
class models). Such cases are what explicit
was designed for.
However, this will not work for cases where direct initialization is used
struct A {
CBigInt n;
A():n(0) { } // ambiguity again
};
In general, explicit
should not be used to resolve internal ambiguities. It should merely be used to forbid the conversion from one type to the other, but not to prefer another constructor over the explicit
constructor. In fact, the new C++0x uniform initializations will not ignore explicit
constructors in a copy initialization context:
CBigInt f() {
return { 0 }; // still ambiguous
}
CBigInt b = { 0 }; // still ambiguous
The rules for uniform initialization is: Both constructors are considered, but if an explicit constructor is chosen, initialization is ill-formed.
The literal 0
is an int
. Assuming you want to be able to accept all integer types, you need to at least add an int
taking constructor. You don't need to add overloads for integer types smaller than int
, because those types prefer int
over other integer conversions or pointers. Assuming you have an int
overload you also need to add overloads for the remaining integer types and, if available and you use it, long long
and unsigned long long
. Ambiguities will then not arise anymore:
CBigInt (int);
CBigInt (unsigned int);
CBigInt (long);
CBigInt (unsigned long);
// CBigInt (long long);
// CBigInt (unsigned long long);
explicit CBigInt (const char *);