Подтвердить что ты не робот

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

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

//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?

4b9b3361

Ответ 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 имеет два).