Не удается вывести тип косвенно вызываемой функции шаблона

#c #function #templates

Вопрос:

Следующий фрагмент кода представляет собой урезанную версию того, что должно стать алгоритмом оптимизации:

 template<typename F>
double helper(F f, double x)
{
    return x;
}

template<typename F, typename L>
double optimize(F f, double x, L line_search)
{
    double y = line_search(f, x);
    return y;
}

int main()
{
    auto f = [](double x){ return (x - 2) * (x - 2); };
    double solution = optimize(f, -2, helper);
}
 

Я параметризовал основную функцию ( optimize ) и вспомогательную функцию ( helper ) с помощью аргумента шаблона F для функции, которую они пытаются минимизировать. Однако код не компилируется; компилятор не может определить тип line_search :

 t04.cpp: In function ‘int main()’:
t04.cpp:17:45: error: no matching function for call to ‘optimize(main()::<lambda(double)>amp;, int, <unresolved overloaded function type>)’
     double solution = optimize(f, -2, helper);
                                             ^
t04.cpp:8:8: note: candidate: template<class F, class L> double optimize(F, double, L)
 double optimize(F f, double x, L line_search)
        ^~~~~~~~
t04.cpp:8:8: note:   template argument deduction/substitution failed:
t04.cpp:17:45: note:   couldn't deduce template parameter ‘L’
     double solution = optimize(f, -2, helper);
 

(Я использую gcc v7.5.0, но я не думаю, что это имеет значение здесь.) Я думаю, что понимаю, почему компилятор не знает тип line_search (он не заглядывает внутрь optimize , чтобы увидеть, как line_search это называется), но я не знаю, как объяснить, каким должен быть правильный тип. Хотел бы я сказать optimize(f, -2, helper<type of f>) , но я не нашел, как это сделать. Что мне нужно изменить в коде?

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

Комментарии:

1. helper это шаблон функции. В какой специализации helper должен работать компилятор optimize(f, -2, helper) ?

2. Почему helper-это шаблон? Это ничего не делает с f. Если есть причина, то вы, возможно, могли бы сделать так optimize(f, -2, helper<decltype(f)>) .

3. @ScottHutchinson: Вы правы, что в этом примере параметр шаблона не используется. Идея состоит в том, что может быть несколько помощников (на самом деле, методы поиска строк), которые выполняют одну и ту же задачу минимизации функции f одной переменной. decltype на самом деле это то, что я искал, сам того не зная.

Ответ №1:

Вы можете добавить тип по умолчанию, для L которого включает F :

 template<typename F>
double helper(F f, double x) {
    return f(x);
}

template<typename F, typename L = double(*)(F, double)>  // <- here
double optimize(F f, double x, L line_search) {
    double y = line_search(f, x);
    return y;
}
 

Затем он найдет правильный экземпляр шаблона, когда вы это сделаете

 double solution = optimize(f, -2, helper);   // helper is helper<decltype(f)>
 

Если helper это шаблон функции, который вы часто используете, вы можете сделать его шаблоном по умолчанию:

 template<typename F, typename L = double(*)(F, double)>
double optimize(F f, double x, L line_search = helper<F>) {  // <- here
    double y = line_search(f, x);
    return y;
}
 

что позволяет звонить optimize без указания помощника:

 double solution = optimize(f, -2);   // helper<decltype(f)> is the default