Fix matching of non-type template parameters when matching template template parameters

Document #: D3579R0 [Latest] [Status]
Date: 2025-01-12
Project: Programming Language C++
Audience: Core Working Group
Reply-to: Matheus Izvekov
<>

1 Introduction

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.

2 Overview

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.

3 Wording

Append to 13.4.4 [temp.arg.template]/4

  • For each non-type template argument AA, if a narrowing conversion ([dcl.init.list]) is required for initializing a variable of the same type as PP from a variable of the same type as AA, the program is ill-formed.

[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

4 References

[P0522R0] James Touton, Hubert Tong. 2016-11-11. DR: Matching of template template-arguments excludes compatible templates.
https://wg21.link/p0522r0
[P3310R5] Matheus Izvekov. 2024-11-18. Solving partial ordering issues introduced by relaxed template template parameter matching.
https://wg21.link/p3310r5