Document #: | D3579R0 [Latest] [Status] |
Date: | 2025-01-12 |
Project: | Programming Language C++ |
Audience: |
Core Working Group |
Reply-to: |
Matheus Izvekov <mizvekov@gmail.com> |
This paper is a follow-up to [P3310R5], and proposes to fix one additional issue which came with the incorporation of [P0522R0] into the standard.
The wording change failed to prevent a narrowing conversion for non-type template parameters when matching a template template-argument to a template-parameter.
This goes against the intent of P0522, which while it preserved the type-theoretically incorrect parameter pack exception, aimed to not add new such cases when matching template template parameters.
Consider the following example:
template<template<short> class> struct A {};
template<short> struct B;
template struct A<B>; // OK, exact match
template<int> struct C;
template struct A<C>; // #1: OK, all 'short' values are valid 'int' values
template<char> struct D;
template struct A<D>; // #2: error, not all 'short' values are valid 'char' values
The intention was that [P0522R0] would allow
#1
, but it
inadvertently also allowed
#2
: the
wording change did not implement the paper’s intent in this case, which
assumed that the ‘at least as specialized’ check would only imply that
“any template argument list that can legitimately be applied to the
template template-parameter is also applicable to the argument
template”.
The new rules delegated this matching to partial ordering of function templates, where a rewrite produced one each for the template parameter and the template argument.
But when matching these function templates against each other in the narrowing case, the template arguments produced from the non-type template parameters are value-dependent, and narrowing conversions are not diagnosed in this case, as in general dependent entities are not diagnosed if they have valid instantiations.
Append to 13.4.4 [temp.arg.template]/4
[Example:
template<template<short> class> struct A {};
template<int> struct B;
template struct A<B>; // OK, not narrowing
template<char> struct C; template struct A<C>; // error: narrowing