#c #templates #template-argument-deduction
#c #шаблоны #шаблон-аргумент-вычеты
Вопрос:
У меня довольно простая проблема с шаблоном. Я хотел иметь некоторые математические функции, которые работают со скалярами и векторами. Для аргументов я хочу, чтобы мои скаляры передавались по копии, а мои векторы — по ссылке. В итоге я использовал шаблонную вспомогательную структуру.
Но когда я использую свои функции, компилятору не удается самостоятельно вывести параметры шаблона. Я не знаю, что я сделал не так, или что я должен сделать по-другому, или если этот подход обречен с самого начала ^^ ‘.
Вот пример:
#include <type_traits>
template <typename T>
struct CopyOrConstRef
{
using Type = std::conditional_t<
std::is_scalar<T>::value,
T,
const std::remove_reference_t<T>amp;
>;
};
template <typename T>
using CopyOrConstRef_t = typename CopyOrConstRef<T>::Type;
template <typename T>
T Lerp(CopyOrConstRef_t<T> _a, CopyOrConstRef_t<T> _b, const float _factor)
{
return (_a * (1.f - _factor)) (_b * _factor);
}
int main()
{
Lerp(0.f, 1.f, 0.5f); // does not work :'(
Lerp<float>(0.f, 1.f, 0.5f); // works as intended
return 0;
}
С сообщениями об ошибках (на msvc):
error C2672: 'Lerp': no matching overloaded function found
error C2783: 'T Lerp(CopyOrConstRef<T>::Type,CopyOrConstRef<T>::Type,const float)': could not deduce template argument for 'T'
Комментарии:
1. На самом деле это не так, как работает вывод аргументов шаблона. Он всегда соответствует точному типу без каких-либо преобразований. Вы передаете
float
, и функция будет принимать только некоторую формуCopyOrConstRef<...>
, поэтому вычет завершается неудачей.2. Итак, я обречен в начале? :, D Есть ли какой-то способ добиться того, что я пытался сделать?
3. Передача
float
по const ref обычно не является проблемой, в частности, с template . Есть вероятность, что вызов функции будет встроен в любом случае.
Ответ №1:
Это не сработает, поскольку все варианты использования T
(которые есть CopyOrConstRef_t<T>
) в списке аргументов Lerp
находятся в не выводимых контекстах:
Не выводимые контексты:
Спецификатор вложенного имени типа, который был указан с использованием квалифицированного идентификатора.
Вот пример из ссылки:
Параметры шаблона не участвуют в выводе аргумента шаблона, если они используются только в не выводимых контекстах. Например,
template<int i, typename T> T deduce(typename A<T>::X x, // T is not deduced here T t, // but T is deduced here typename B<i>::Y y); // i is not deduced here
Ваш пример тот же, за исключением того, что нет аргумента, который можно вывести, и у вас есть шаблон псевдонима для аргументов (что ничего не меняет).