Вывод возврата и типа параметра из std :: function, переданного в качестве аргумента функции шаблона? - PullRequest
2 голосов
/ 04 апреля 2019

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

В предложении: возможно ли объявить шаблонную функцию, которая принимает параметр std::function и вывести параметры шаблона как для типа возвращаемого значения, так и для типов параметров функции?Пример:

//this works to pass the std::function in
template<class T>
void doSomething(std::function<T> f) {
    f();
}

//this is more what i am looking for - can R and P be deduced automatically - does not work!
template<class R, class P>
void doSomethingElse(std::function<R(P)> f) {
    f();
}

Это потому, что сигнатура функции или тип функции рассматривается как одна вещь, и как таковая не может быть «разбита»?Я понимаю, что есть decltype и std::result_of, но не могу придумать, как я мог бы использовать их здесь.

В качестве дополнительного пункта, как я мог бы расширить второй пример, чтобы иметь несколько параметров и вычетов, используя вариационные шаблоны?

1 Ответ

3 голосов
/ 04 апреля 2019
template<class R, class P>
void doSomethingElse(std::function<R(P)> f) {
    f(P{});
}

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

template<class R, class... Args, class... Ts>
void doSomethingElse(std::function<R(Args...)> f, Ts&&... args) {
    f(std::forward<Args>(args)...);
}

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

С C ++ 17 и вычет аргумента шаблона класса (CTAD) это больше не проблема. Мы можем создать перегрузку, которая принимает любой тип, а затем с помощью CTAD создать std :: function для заполнения типов для нас. Это будет выглядеть как

template<class Func, class... Args>
void doSomethingElse(Func&& f, Args&&... args) {
    doSomethingElse(std::function{std::forward<Func>(f)}, std::forward<Args>(args)...);
}

template<class R, class... Args, class... Ts>
void doSomethingElse(std::function<R(Args...)> f, Ts&&... args) {
    f(std::forward<Args>(args)...);
}

И теперь все, что не является std::function, перейдет к void doSomethingElse(Func&& f, Args&&... args), преобразуется в std::function и будет передано void doSomethingElse(std::function<R(Args...)> f, Args&&... args), чтобы вы могли использовать тип возвращаемого значения и тип аргумента (ов) ( s) там.

...