简体   繁体   中英

Ambiguous call to overloaded integer constructor

I shall provide these two constructors.

BigUnsigned(int value)
    :BigUnsigned(static_cast<unsigned long long>(value)){
}
BigUnsigned(unsigned long long value);

The problem is the call is ambiguous for some argument values. According to this answer , that refers the C++11 standard,

the type of an integer literal is the first of the corresponding list in Table 6 in which its value can be represented.

Table 6 is here

int
long int
long long int

Therefore, in my case, the type of the constructor argument (integer literal) if it belongs to the range...

<0, numeric_limits<int>::max()> is int

---> calling BigUnsigned(int)

(numeric_limits<int>::max(), numeric_limits<long int>::max()> is long int

---> ambiguous

(numeric_limits<long int>::max(), too big literal) is long long int

---> ambiguous

How can I solve the ambiguity without declaring any more constructors or explicitly typecasting the argument?

This question on integer promotion and integer conversion might be useful. I still don't know which of them applies in my case, though.

One fundamental problem here is that a decimal literal will never be deduced as an unsigned type. Therefore, a decimal literal that's too large to fit in an int end up requiring a signed->unsigned conversion in one case, and a long->int conversion in the other. Both of these are classed as "integral conversions", so neither is considered a "better" conversion, and the overload is ambiguous.

As to possible ways to deal with this without explicitly casting the argument or adding more constructors, I can see a couple.

At least for a literal, you could add a suffix that specifies that the type of the literal is unsigned:

BigUnsigned a(5000000000U); // unambiguous

Another (that also applies only to literals) would be to use a hexadecimal or octal literal, which (according to part of table 6 that isn't quoted in the question) can be deduced as either signed or unsigned. This is only a partial fix though--it only works for values that will deduce as unsigned. For a typical system with 32-bit int, 32-bit long, and 64-bit long long, I believe it'll come out like this:

在此输入图像描述

So for a parameter large enough that it won't fit in a signed long long, this gives an unambiguous call where the decimal constant would still have been ambiguous.

For people who've worked with smaller types, it might initially seem like the conversion from unsigned long to unsigned long long would qualify as a promotion instead of a conversion, which would make it preferable. And indeed, if (for example) the types involved were unsigned short and unsigned int , that would be exactly true--but that special preference is only given for types with conversion ranks less than int (which basically translates to: types that are smaller than int).

So that fixes the problem for one range of numbers, but only if they're literals, and only if they fall into one specific (albeit, quite large) range.

For the more general case, the only real cure is to change the interface. Either remove the overload for int , or add a few more ctor overloads, specifically for unsigned and for long long . These can be delegating constructors just like the existing one for int , if you decide you need them at all (but it's probably better to just have the one for unsigned long long and be done with it).

I had the same Problem. Also with some Big-Integer classes. However the literal-only solution did not work for me since I need to convert totally different kinds of (Big-)Ints between each other. I tried to avoid the excessive implementation of constructors. I solved the problem like this:

  template <std::same_as<MyOtherBigInt> T>
  explicit constexpr MyBigInt(T pValue) noexcept;

This stops the special MyOtherBigInt-Constructor from being called with any other integer.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM