Как псевдонимы шаблонов влияют на вычет параметров шаблона?
В С++ 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:
Когда идентификатор шаблона ссылается на специализацию шаблона псевдонимов, он эквивалентен ассоциированному типу, полученному путем подстановки его шаблонных аргументов для параметров шаблона в идентификаторе типа шаблона псевдонимов. [Примечание. Имя шаблона псевдонима никогда не выводится. - конечная нота]
Ниже приведен пример, в котором фактически указано, что бессмысленно использовать шаблон-псевдоним в шаблоне функции и надеяться вывести аргумент шаблона. Это, по-видимому, применимо даже для ситуации, которая не связана с вложенными типами.