Как псевдонимы шаблонов влияют на вычет параметров шаблона?

В С++ 03 вычитание параметра шаблона не встречается в некоторых контекстах. Например:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
void f(typename A<T>::type);

int main()
{
    B<int> b;
    f(b);  // ERROR: no match
}

Здесь int не выводится для T, потому что вложенный тип, такой как A<T>::type, является невыводимым контекстом.

Если бы я написал такую ​​функцию:

template <typename T> struct B {};

template <typename T>
void f(B<T>);

int main()
{
    B<int> b;
    f(b);
}

все отлично, потому что B<T> - выведенный контекст.

В С++ 11, однако, шаблонные псевдонимы могут использоваться для маскировки вложенного типа в синтаксисе, аналогичном второму примеру. Например:

template <typename T> struct B {};

template <typename T>
struct A
{
    typedef B<T> type;
};

template <typename T>
using C = typename A<T>::type;

template <typename T>
void f(C<T>);

int main()
{
    B<int> b;
    f(b);
}

Будет ли в этом случае работать с аргументом шаблона? Другими словами, являются ли псевдонимы шаблонов выведенным контекстом или не выводимым контекстом? Или они наследуют выведенный/не выводимый статус того, что они называют?

Ответы

Ответ 1

Другими словами, являются ли псевдонимы шаблонов выведенным контекстом или не выводимым контекстом?

Они выводятся как эквивалентный код без использования псевдонимов шаблонов. Например

template<typename T>
using ref = T&;

template<typename T>
void f(ref<T> r);

Теперь вы можете вызывать f(x), а T будет выводиться отлично. При времени определения f уже ref<T> заменяется типом T&. И T& - это выведенный контекст.

В вашем случае C<T> заменяется на typename A<T>::type, и это не выводимый контекст для T, поэтому T не может быть выведен.

Ответ 2

Представьте себе следующее:

template <typename T> struct Foo { typedef   T type; }
template <> struct Foo<char>     { typedef int type; }

template <typename T> using mytype = typename Foo<T>::type;

template <typename T> void f(mytype<T>);

Теперь, если я хочу int n; f(n);, как я могу решить, хочу ли я T = int или T = char? Вся проблема, которая не затрагивается псевдонимами шаблонов, заключается в том, что вы не можете выводить назад все, что могло бы что-то определить.

Ответ 3

Я думаю, что соответствующая цитата в стандарте С++ - это 14.5.7 [temp.alias] параграф 2:

Когда идентификатор шаблона ссылается на специализацию шаблона псевдонимов, он эквивалентен ассоциированному типу, полученному путем подстановки его шаблонных аргументов для параметров шаблона в идентификаторе типа шаблона псевдонимов. [Примечание. Имя шаблона псевдонима никогда не выводится. - конечная нота]

Ниже приведен пример, в котором фактически указано, что бессмысленно использовать шаблон-псевдоним в шаблоне функции и надеяться вывести аргумент шаблона. Это, по-видимому, применимо даже для ситуации, которая не связана с вложенными типами.