Почему шаблонный вывод не работает здесь?
Я создал две простые функции, которые получают параметры шаблона и пустую структуру, определяющую тип:
//S<T>::type results in T&
template <class T>
struct S
{
typedef typename T& type;
};
//Example 1: get one parameter by reference and return it by value
template <class A>
A
temp(typename S<A>::type a1)
{
return a1;
}
//Example 2: get two parameters by reference, perform the sum and return it
template <class A, class B>
B
temp2(typename S<A>::type a1, B a2)//typename struct S<B>::type a2)
{
return a1 + a2;
}
Тип аргумента применяется к структуре S для получения ссылки. Я называю их целыми значениями, но компилятор не может вывести аргументы:
int main()
{
char c=6;
int d=7;
int res = temp(c);
int res2 = temp2(d,7);
}
Ошибка 1 Ошибка C2783: 'A temp (S:: type) ': не удалось вывести аргумент шаблона для 'A'
Ошибка 2 ошибки C2783: 'B temp2 (S:: type, B) ': не удалось вывести аргумент шаблона для 'A'
Почему это происходит? Трудно ли увидеть, что аргументы шаблона char и значения int?
Ответы
Ответ 1
Как и в первом примечании, имя имени используется при упоминании зависимого имени. Так что вам здесь не нужно.
template <class T>
struct S
{
typedef T& type;
};
Что касается создания экземпляра шаблона, проблема заключается в том, что typename S<A>::type
характеризует неразрешенный контекст для A. Когда параметр шаблона используется только в неразрешенном контексте (случай для A в ваших функциях), он не учитывается для аргумента шаблона вычет. Подробности приведены в разделе 14.8.2.4 Стандарта С++ (2003).
Чтобы заставить ваш вызов работать, вам необходимо явно указать тип:
temp<char>(c);
Ответ 2
Это похоже на неразрешенный контекст. Согласно стандарту С++ 14.8.2.4/4:
Неопределенные контексты:
- Вложенное имя-спецификатор типа, который был указан с использованием идентификатора с квалификацией.
- Тип, который является идентификатором шаблона, в котором один или несколько аргументов-шаблонов являются выражением, которое ссылается на шаблон-параметр.
Когда имя типа указано таким образом, который включает неопределенный контекст, все типы, которые содержат это имя типа, также не определены. Однако составной тип может включать как выведенные, так и недетерминированные типы. [Пример. Если тип указан как A<T>::B<T2>
, то как T
, так и T2
не указаны. Аналогично, если тип указан как A<I+J>::X<T>
, I
, J
и T
не указаны. Если тип указан как void f(typename A<T>::B, A<T>)
, то T
в A<T>::B
не указывается, а выводится T
в A<T>
. ]
Ответ 3
Вычет производится в прямом направлении:
template <class T> void f(T);
f(2); // can deduce int from T
Почему это происходит?
Он не работает в обратном направлении (ваш пример):
template <class A> void g(typename S<A>::type);
Трудно ли увидеть, что аргументы шаблона char и значения int?
Выдача шаблона может делать некоторые магические (Тьюринга) вещи, но я не думаю, что это один из них.
Вы можете использовать что-то вроде (untested):
template <class SA> void h(SA a1)
{
STATIC_ASSERT(same_type<SA, S<A>::type>::value);
typedef typename SA::type A;
...
}
Использование вашей любимой библиотеки static assert (Boost имеет два).