Вывод шаблона C ++ из лямбды - PullRequest
       0

Вывод шаблона C ++ из лямбды

0 голосов
/ 07 сентября 2018

У меня есть функция, которая принимает два std::function s в качестве аргументов. Параметр второй функции имеет тот же тип, что и результат первой.

Я написал такой шаблон функции:

template<typename ResultType>
void examplFunction(std::function<ResultType()> func, std::function<void(ResultType)> func2) {
  auto x = func();
  func2(x);
}

Я могу назвать это с:

void f() {
  examplFunction<int>([]() { return 1; },   //
                      [](int v) { std::cout << "result is " << v << std::endl; });
}

Есть ли способ избавиться от <int> в examplFunction<int> и позволить компилятору определить тип ResultType?

Ответы [ 4 ]

0 голосов
/ 07 сентября 2018

Ответ Angew отличный (и должен быть принятым ответом), но он пропускает незначительную деталь проверки того, что функция section ничего не возвращает. Для этого вам нужно использовать черту типа std::is_void и std :: enable_if:

template<class F1, class F2>
void examplFunction(F1 func, F2 func2, std::enable_if_t<std::is_void_v<decltype(func2(func()))>, void*> sfinae = nullptr) {
    auto x = func();
    func2(x);
}

Это очевидное является более многословным и трудным для чтения, если вы не знакомы с чертами типов и SFINAE, поэтому, вероятно, это не лучший путь вперед, если вам не нужно, чтобы F2 возвращал void.

0 голосов
/ 07 сентября 2018

Да, есть.

template<typename ResultType>
void examplFunction_impl(std::function<ResultType()> func, std::function<void(ResultType)> func2) {
    auto x = func();
    func2(x);
}

template<class F1, class F2>
void examplFunction(F1&& f1, F2&& f2)
{
    using ResultType = decltype(f1());
    examplFunction_impl<ResultType>(std::forward<F1>(f1), std::forward<F2>(f2));
}

Демо

В этом случае вам требуется, чтобы f1 был вызван без аргументов, чтобы вы могли выяснить тип возвращаемого значения в вспомогательной функции. Затем вы вызываете реальную функцию, явно указав этот тип возвращаемого значения.

Вы могли бы добавить SFINAE , чтобы убедиться, что эта функция участвует только в разрешении перегрузки, когда f1 действительно может быть вызван подобным образом (и если f2 также может быть вызвано с возвращаемым значением f1).

Хотя я должен согласиться с @Angew, что в данном примере в std::function нет необходимости. Конечно, в реальной ситуации это может отличаться.

0 голосов
/ 07 сентября 2018

std::function имеет шаблонный (и в противном случае неограниченный) конструктор, поэтому вывести его из простого типа аргумента не так просто. Если эти аргументы по-прежнему должны быть std::function с, вы можете пропустить один <int> по цене двух std::function с, а гиды удержания сделают все остальное:

void f() {
    examplFunction(std::function([]() { return 1; }),   //
                   std::function([](int v) { std::cout << "result is "
                                             << v << std::endl; }));
}

Интересный факт, что это не всегда работает. Например, в текущей реализации libc ++ отсутствуют руководства для std::function, что нарушает стандарт.

0 голосов
/ 07 сентября 2018

Вам действительно нужно std::function там?std::function полезно, когда вам нужно стирание типа .С шаблонами вы можете вообще пропустить это:

template<class F1, class F2>
void examplFunction(F1 func, F2 func2, decltype(func2(func()))* sfinae = nullptr) {
  auto x = func();
  func2(x);
}

Параметр sfinae гарантирует, что функция может быть вызвана только с такими функциями, что func2 может быть вызван с результатом func.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...