«Ошибка вывода / замены аргумента шаблона» с функциональным объектом с пакетом параметров - PullRequest
1 голос
/ 05 мая 2019

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

#include <iostream>
#include <functional>

template<class... Ts>
void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
{
    function(parameters...);
}

void myFunc(const std::string& output)
{
    std::cout << output << std::endl;
}

int main() 
{
    callFunction<const std::string&>(&myFunc, "Hello world");
    return 0;
}

Когда я запускаю приведенный выше код в Ideone , я получаю эту ошибку:

prog.cpp: In function ‘int main()’:
prog.cpp:17:57: error: no matching function for call to ‘callFunction(void (*)(const string&), const char [12])’
  callFunction<const std::string&>(&myFunc, "Hello world");
                                                         ^
prog.cpp:5:6: note: candidate: template<class ... Ts> void callFunction(const std::function<void(Ts ...)>&, Ts ...)
 void callFunction(const std::function<void(Ts...)>& function, Ts... parameters)
      ^~~~~~~~~~~~
prog.cpp:5:6: note:   template argument deduction/substitution failed:
prog.cpp:17:57: note:   mismatched types ‘const std::function<void(Ts ...)>’ and ‘void (*)(const string&) {aka void (*)(const std::__cxx11::basic_string<char>&)}’
  callFunction<const std::string&>(&myFunc, "Hello world");

1 Ответ

2 голосов
/ 05 мая 2019

Простое предложение: получить вызываемое имя как выведенное имя типа, а не как std::function

Я имею в виду (добавив также совершенную пересылку)

template <typename F, typename ... Ts>
void callFunction(F const & func, Ts && ... pars)
 { func(std::forward<Ts>(pars)...); }

и, очевидно, назовите егоничего не объясняя

callFunction(&myFunc, "Hello world");

Это как дополнительное преимущество, позволяющее избежать преобразования вызываемого в std::function.

В любом случае, я вижу две проблемы в вашем коде:

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

Это не ваш случай, потому что функция получает std::string const & и вы передаете в качестве аргумента aстроковый литерал "Hello world", который является char const [12], который является другим типом.

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

Вы можете решить получение два список типов

template <typename ... Ts1, typename Ts2>
void callFunction (std::function<void(Ts1...)> const & function,
                   Ts2 && ... parameters)
 { function(std::forward<Ts2>(parameters)...); }

но теперь у нас есть вторая проблема

2) Вы передаете функцию указателя (&myFunc), где callFunction() ждутstd::function.

У нас проблема с куриным яйцом, потому что &myFunc можно преобразовать в std::function, но не в std::function.

Так что компилятор может 'выводит список типов Ts... из &myFunc, потому что не является std::function и не может преобразовать &myFunc в std::function, потому что не знает список типов Ts....

Я вижу, что вы объяснили тип first в списке Ts..., но этого недостаточно, потому что список Ts... является переменным, поэтому компилятор не знает, что существует толькотип в списке Ts....

Простое решение этой проблемы - передать функцию как простой выведенный тип F.

В противном случае, если вы написали callFunction() сдва типа шаблонов списков, вы можете передать std::function в функцию

std::function<void(std::string const &)>  f{&myFunc};

callFunction(f, "Hello world");

, но я не думаю, что это удовлетворительное решение.

...