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

#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
  

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