Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How implicit conversion works for non-type template parameters?

I guess (certain) implicit conversions apply when passing non-type template parameters. For example, there should be a conversion from int to std::size_t for expressions like std::array<int, 7>. However, consider the following code:

template <bool>
void f() {
    std::cout << "false\n";
}

template <>
void f<true>() {
    std::cout << "true\n";
}

int main() {
    f<1>();
    f<4>();
    f<0>();
}

I expect int to be implicitly converted to bool here. But the behaviors are different on VC, GCC, and clang.

On VC, true, false, and false are printed, which is really weird to me.

On GCC, true, true, and false are printed, which is what I expect.

While on clang, the code does not compile at all due to the statement f<4>();.

candidate template ignored: invalid explicitly-specified argument for 1st template parameter

So, what does the standard say about this? What is the implicit conversion rule for non-type template parameters?

like image 369
Lingxi Avatar asked Jan 28 '15 04:01

Lingxi


1 Answers

From the standard (§14.3.2/5):

The following conversions are performed on each expression used as a non-type template-argument. If a non-type template-argument cannot be converted to the type of the corresponding template-parameter then the program is ill-formed.

  • For a non-type template-parameter of integral or enumeration type, conversions permitted in a converted constant expression (5.19) are applied.

In §5.19, we learn (emphasis mine):

An integral constant expression is an expression of integral or unscoped enumeration type, implicitly converted to a prvalue, where the converted expression is a core constant expression. ... A converted constant expression of type T is an expression, implicitly converted to a prvalue of type T, where the converted expression is a core constant expression and the implicit conversion sequence contains only user-defined conversions, lvalue-to-rvalue conversions (4.1), integral promotions (4.5), and integral conversions (4.7) other than narrowing conversions (8.5.4). [ Note: such expressions may be used in new expressions (5.3.4), as case expressions (6.4.2), as enumerator initializers if the underlying type is fixed (7.2), as array bounds (8.3.4), and as integral or enumeration non-type template arguments (14.3). —end note ]

So narrowing conversions (like converting 4 to bool) are explicitly disallowed for integral constant expressions, which are required in this case as a non-type template argument. That makes the call f<4>() ill-formed.

I believe Clang is correct in issuing an error, and GCC and VC are both nonconforming for not issuing any diagnostic.

[Update] This is GCC Bug #57891, looks like it's currently unassigned.

like image 123
Barry Avatar answered Oct 26 '22 05:10

Barry