Home > Mobile >  Inconsistent implicit conversion behavior
Inconsistent implicit conversion behavior

Time:07-27

I encountered a case where I cannot understand the implicit conversion behavior in c . The code is the following:

template <bool b, int i, unsigned... us>
void foo() {}

template <int i, unsigned... us>
void foo() {return foo<false, i, us...>();}

int main()
{
    foo<true, -1, 0ul, 1ul, 2ul>(); // compiles with clang and gcc > 8 (gcc<=8 gives ambiguous function call)
    foo<true,  1, 0ul, 1ul, 2ul>(); // ambiguous function call error
    foo<-1, 0ul, 1ul, 3ul>(); // compiles with clang and gcc > 8 (gcc<=8 gives ambiguous function call)
    foo< 1, 0ul, 1ul, 3ul>(); // ambiguous function call error
}

For line 1 and 2 in main(), the compiler seems to implicitly cast int to unsigned only for positive integers (this is understandable but is there a rule for this?)

For line 3 and 4 in main(), the compiler seems to implicitly cast int to bool only for positive integers. I cannot understand why.

Background: Ideally, I want to get a similar construct to work which effectly leads to a default value for the bool template parameter. But because of the parameter pack and c implicit builtin conversions, this seems to be difficult.

CodePudding user response:

A non-type template argument is required to be a converted constant expression of the template parameter's type.

A converted constant expression specifically does not allow for narrowing conversions, which in the case of constant expression evaluation between integral types means that the conversion is not allowed if it would change the numeric value.

This is specific to the converted constant expression requirement. If these were function parameter and argument, then implicit conversion of -1 to unsigned would be allowed and it also has a well-defined result, although obviously not with the same numeric value of -1.

Therefore in foo<true, -1, 0ul, 1ul, 2ul>(); the template which requires unsigned in that position for -1 is indeed not viable as an overload candidate.

Boolean conversions, meaning conversions from other scalar types to bool are not listed in the list of conversions allowed for a converted constant expression at all (see [expr.const]/10), which as far as I can tell should make the overload with bool in the first position non-viable for both foo<-1, 0ul, 1ul, 3ul>(); and foo< 1, 0ul, 1ul, 3ul>();. I am not sure why the compilers consider the latter ambiguous anyway. According to the resolution of CWG issue 1407 as not-a-defect, the conversion from int template argument to bool template parameter is indeed not allowed, but compilers are behaving non-conforming and seem to treat it like an integral type with range 0/1.

I don't know what problem GCC <8 has. I guess it was just a bug that it considered the overload ambiguous.

  • Related