Итерация по кортежу функторов в c ++ 11 - PullRequest
0 голосов
/ 06 июня 2018

У меня есть std::tuple функторов (неизвестной арности), которые, как ожидается, все будут возвращать один и тот же тип, поэтому что-то вроде:

typedef functor std::function<bool()>;
std::tuple<functor, functor, functor...> functors;

Я бы хотел перебрать функторы, оценивая каждыйчлен, пока я не найду тот, который преуспевает, иначе отказКак я могу добиться этого в C ++ 11?

Ответы [ 2 ]

0 голосов
/ 06 июня 2018

Просто используйте правильный контейнер - std::vector вместо std::tuple:

using functor = std::function<bool()>;
using functors = std::vector<functor>;

, и я думаю, что совершенно очевидно, как перебирать std::vector

0 голосов
/ 06 июня 2018

Не особенно креативно, но ...

Если вы создаете функцию foo() следующим образом

template <typename ... Args>
bool foo (std::tuple<Args...> const & tf)
 { return bar<0>(tf); }

, которая вызывает, начиная с индекса шаблона 0, следующую пару шаблонов (SFINAE включен / отключен) альтернативные функции

template <std::size_t I, typename ... Args>
typename std::enable_if<(I >= sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const &)
 { return false; }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I < sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const & tf)
 { return baz(std::get<I>(tf)) || bar<I+1U>(tf); }

и дополнительная функция baz() для вызова одиночных функторов

bool baz (functor const & f)
 { return f(); }

Полагаю, вы можете получить то, что хотите.

Ниже приведен полный рабочий пример

#include <tuple>
#include <iostream>
#include <functional>

using functor = std::function<bool()>;

bool baz (functor const & f)
 { return f(); }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I >= sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const &)
 { return false; }

template <std::size_t I, typename ... Args>
typename std::enable_if<(I < sizeof...(Args)), bool>::type
   bar (std::tuple<Args...> const & tf)
 { return baz(std::get<I>(tf)) || bar<I+1U>(tf); }

template <typename ... Args>
bool foo (std::tuple<Args...> const & tf)
 { return bar<0>(tf); }

bool f0 () { std::cout << "f0 "; return false; }
bool f1 () { std::cout << "f1 "; return false; }
bool f2 () { std::cout << "f2 "; return false; }
bool f3 () { std::cout << "f3 "; return false; }
bool f4 () { std::cout << "f4 "; return true; }
bool f5 () { std::cout << "f5 "; return false; }
bool f6 () { std::cout << "f6 "; return false; }
bool f7 () { std::cout << "f7 "; return false; }
bool f8 () { std::cout << "f8 "; return false; }
bool f9 () { std::cout << "f9 "; return false; }

int main ()
 {
   auto tf = std::make_tuple(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9);

   foo(tf);
 }

Очевидно, что вы можете избежать использования baz() и просто вызывать функторы следующим образом

 return std::get<I>(tf)() || bar<I+1U>(tf);

, но вы теряете проверкуArgs... типы.

...