Разница в вычете специализации шаблона и псевдонима шаблона - PullRequest
10 голосов
/ 03 мая 2019

Я изо всех сил пытаюсь понять, как работает удержание в следующем случае:

template<class Category, Category code>
struct AImpl
{ };

template<class Category, Category code>
struct AHelper
{
    using type = AImpl<Category, code>;
};

template<class Category, Category code>
using A = typename AHelper<Category, code>::type;

template<int code>
void doSomething(A<int, code> object)
{
}

Ниже приведен тестовый код:

A<int, 5> a1;
doSomething(a1); // This does not compile
doSomething<5>(a1); // This compiles

Почему a1 не выводится в этом контексте?

Если вместо этого изменить A следующим образом:

template<class Category, Category code>
struct A
{ };

Оба работают.Кто-нибудь знает почему?

[править] вопрос, связанный с Смешивание псевдонимов и специализаций шаблонов

1 Ответ

9 голосов
/ 03 мая 2019

Почему a1 не выводится в этом контексте?

Потому что аргумент шаблона doSomething появляется в не выводимом контексте. Шаблон псевдонима почти точно соответствует псевдониму. А ваш определяется следующим образом:

template<class Category, Category code>
using A = typename AHelper<Category, code>::type;

Чтобы вывести code, компилятор должен будет вывести что-то слева от ::, и это не выводимый контекст. Вывод аргумента шаблона даже не попытается вывести что-либо, если он появится в качестве аргумента слева от оператора разрешения контекста.

Недаром этот контекст не выводится. Помните, что шаблоны могут быть специализированными. Я мог бы добавить это:

template<Category code>
struct AHelper<int, code>
{
    using type = BImpl<code>; // My own class!
};

Компилятору необходимо просмотреть весь код во всей программе и попробовать все типы, чтобы убедиться, что ничего страшного не происходит, чтобы убедиться, что a1 действительно совпадает с typename AHelper<Category, code>::type. Это трудно Таким образом, отображение с помощью мета-функций является только улицей с односторонним движением. Вы не можете попросить компилятор выводить тип источника (или не тип аргумента) из целевого типа.

...