Согласование частичных специализаций шаблона шаблона

N4527 14.5.5.1 [temp.class.spec.match]

2 Частичная специализация соответствует данному фактическому списку аргументов шаблона, если аргументы шаблона частичной специализации могут быть выведены из фактического списка аргументов шаблона.

template<class T1, class T2, int I> class A             { }; // #1
template<class T, int I>            class A<T, T*, I>   { }; // #2
template<class T1, class T2, int I> class A<T1*, T2, I> { }; // #3
template<class T>                   class A<int, T*, 5> { }; // #4
template<class T1, class T2, int I> class A<T1, T2*, I> { }; // #5

A<int, int, 1>   a1; // uses #1
A<int, int*, 1>  a2; // uses #2, T is int, I is 1
A<int, char*, 5> a3; // uses #4, T is char
A<int, char*, 1> a4; // uses #5, T1 is int, T2 is char, I is 1
A<int*, int*, 2> a5; // ambiguous: matches #3 and #5

3 Аргумент шаблона непигового типа также можно вывести из значения фактического аргумента шаблона параметра непигового типа первичного шаблона. [Пример: объявление a2 выше. -end пример]

4 В имени типа, которое относится к специализации шаблона класса (например, A<int, int, 1>), список аргументов должен сопоставьте список параметров шаблона основного шаблона. Шаблонными аргументами специализации являются выводится из аргументов первичного шаблона.

В правиле 3 пример показывает, что I выводится из третьего фактического аргумента шаблона 1, это то, что говорит правило2. Так как второе предложение правила4, я думаю, что он повторяет то, что говорит правило2.

Каковы различия между ними (правило2, правило3 и правило4)?

Другими словами, у нас уже есть правило 2, каковы намерения (значение) правила 3 ​​и второе предложение правила4, почему они здесь?

Ответы

Ответ 1

Я думаю, что правило [temp.class.spec.match] 14.5.5.1\2 может быть переписано так, не изменяя его смысл:

[temp.class.spec.match] 14.5.5.1\2 (изменено)

Частичная специализация соответствует данному фактическому списку аргументов шаблона если шаблонные аргументы частичной специализации могут быть выведены из фактического списка аргументов шаблона согласно 14.8.2.5, где P это список аргументов частичной специализации из его simple-template-id и A - фактический список аргументов шаблона.

Правило [temp.deduct.type] 14.8.2.5\1 определяет процесс вывода из типов (я не уверен только о шаблонах), поэтому существует необходимость в правиле [temp.class.spec.match] 14.5.5.1\3, который добавляет к случаям 14.5.5.1\2 с несимметричными параметрами шаблона первичного шаблона, который не являются (частично) специализированными в частичной специализации.

Правило [temp.class.spec.match] 14.5.5.1\4, как вы отметили в комментариях выше (1, 2), это просто пояснение, что аргументы шаблона в идентификаторе шаблона соответствуют параметрам шаблона первичного шаблона, а не его частичным специализациям, которые могут иметь список шаблонов-параметров s. Более того, второе предложение правила, скорее всего, утверждает, что неявный список аргументов шаблона первичного шаблона (14.5.5\4) выводится (!) В соответствии с [temp.deduct. type] 14.8.2.5\9 из списка фактических аргументов. Таким образом, фразы "неявный список аргументов шаблона первичного шаблона" и "аргументы шаблона специализации" подразумевают одно и то же, а фразы "аргументы первичного шаблона" и "фактический список аргументов шаблона" подразумевают другую вещь... Но также может быть, что авторы намеревались написать это:

[temp.class.spec.match] 14.5.5.1\4 (изменено)

В имени типа, которое относится к специализации шаблона класса, список аргументов должен соответствовать списку параметров шаблона основного шаблона. Шаблонные аргументы частичной специализации выводятся из аргументов первичного шаблона.

Все, что...

Ответ 2

Различия между правилом 2 и правилом четыре являются вторым и третьим параметром шаблона. В примере три:

A<int, char*, 5> a3; // uses #4, T is char

Он использует правило4, потому что третий параметр явно специализируется на const int 5, а второй параметр специализирован для приема типа указателя; его уникальная специализация class A.

Я рассматриваю каждую специализацию как конкретный вид класса, и каждый экземпляр имеет уникальную подпись (аналогичную функции перегрузки). Компилятор собирается выбрать специализацию, которая соответствует используемой подписи.

Правило три имеет смысл без правила пять, поэтому после устранения правила пять целью третьего правила было бы специализировать любые типы имен class A, которые: a) do not use a const int 5 for the third parameter b) do not use a pointer or as the second parameter c) do not use a `int` in the second parameter.

Так как не в ваших примерах используется уникальная подпись правила 3, не из них используется правило 3 (если мы удалим двусмысленное правило5).

Это может быть лучше понять, если вы посмотрите только на схему template<...> специализации, а не на подпись <> специализации. Компилятор просматривает схему шаблонов, прежде чем смотреть на специализацию. Кроме того, все другие специализации class A определяют правила для любой новой специализации. Чтобы понять намерения специализации, вы должны понимать намерения всех других специализаций, а намерение специализации не определяется стандартом, определяемым тем, кто реализовал специализацию; то есть. детали реализации специализации действительно определяют намерение.