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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With