Почему вывод аргумента шаблона здесь не работает?

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

//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;
}

Тип аргумента применяется к struct 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?

3 ответа

Решение

Так же, как первое примечание, имя typename используется, когда вы упоминаете зависимое имя. Так что тебе здесь не нужно.


template <class T>
struct S
{
    typedef T& type;
};

Что касается создания шаблона, проблема в том, что typename S<A>::type характеризует невыпущенный контекст для A. Когда параметр шаблона используется только в неведучим контексте (случай A в ваших функциях), он не учитывается при выводе аргумента шаблона. Подробности в разделе 14.8.2.4 Стандарта C++ (2003).

Чтобы ваш звонок работал, вам нужно явно указать тип:


temp<char>(c);

Это выглядит как недоопределенный контекст. Согласно стандарту C++ 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> выводится. ]

Удержание работает в прямом направлении:

template <class T> void f(T);

f(2); // can deduce int from T

Почему это происходит?

Это не работает в обратном направлении (ваш пример):

template <class A> void g(typename S<A>::type);

Трудно ли увидеть, что аргументы шаблона - это значения типа char и int?

Вычисление шаблона может сделать некоторые магические (завершенные по Тьюрингу) вещи, но я не думаю, что это одна из них.

Вы можете использовать что-то вроде (не проверено):

template <class SA> void h(SA a1)
{
    STATIC_ASSERT(same_type<SA, S<A>::type>::value);
    typedef typename SA::type A;

    ...
}

Использование вашей любимой статической библиотеки утверждений (Boost имеет два).

Другие вопросы по тегам