Соответствие параметров шаблонов переменных в std::function

У меня есть следующий код:

#include <iostream>
#include <functional>

template<typename Return, typename... Params>
void func(std::function<Return(Params... )> x) {}

void f(double) {}

int main() {
    //func<void, double>(f); // compile error here in the variadic case
    func(std::function<void(double)>(f));
}

У меня есть 2 вопроса:

1. Я не понимаю, почему линия func<void, double>(f); дай мне ошибку компиляции

/Users/vlad/minimal.cpp:10:5: error: no matching function for call to 'func'
    func<void, double>(f); // compile error here in the variadic case
    ^~~~~~~~~~~~~~~~~~
/Users/vlad/minimal.cpp:5:6: note: candidate template ignored: could not match 'function<void (double, type-parameter-0-1...)>' against 'void (*)(double)'
void func(std::function<Return(Params... )> x) {}
     ^
1 error generated.

тогда как, если я приведу параметр f к std::function (как в строке без комментариев) это работает.

2. И самая загадочная проблема заключается в том, что, если я использую не вариационную версию func (т.е. просто заменить typename... от typename так в действительности func занимает std::function<Return(Params)> в качестве параметра), то закомментированная строка в main работает по желанию. Есть идеи почему?

1 ответ

Решение

Я не понимаю, почему линия func<void, double>(f); дай мне ошибку компиляции

Компилятор не знает, что вы хотите Params быть точно doubleдумает, может быть, вы хотите, чтобы он выводил пакет с большим количеством элементов, таких как double, int, void*, char или же double, double, double или какой-то другой пакет типов, и он не знает, как вывести это из аргумента f,

В теории могут быть и другие специализации std::function который может быть конструктивным из f и который позволит компилятору выводить пакет из более чем одного типа для Params (это не может знать, что это не так, не создавая все возможные специализации std::function и тестирование их, что неосуществимо.

тогда как, если я приведу параметр f к std::function (как в строке без комментариев) это работает.

Потому что теперь компилятор может выводить Params правильно.

И самая загадочная проблема заключается в том, что, если я использую не вариадическую версию func [...] тогда прокомментированная строка в основном работает как требуется. Есть идеи почему?

Потому что теперь компилятор знает, что Params это один тип, а не пакет из нуля или более типов, поэтому, когда вы говорите, func<void, double> это знает Params является double, и не double, int, void*, char или какой-то другой пакет параметров.

Отредактируйте в ответ на ваш комментарий, учтите это:

template<typename T, typename U, typename V>
int func(T t, U u, V v)
{ return 0; }

int i = func<int, char>(1, '2', "three");

Я дал только явный аргумент шаблона для двух параметров, так что третий еще должен быть выведен.

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

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