c ++ Как оценить список функций? - PullRequest
0 голосов
/ 08 мая 2020

Я создаю библиотеку C ++, позволяющую пользователям оценивать список функций. Например, пользователь предоставит три функции

A mapper1(B);
B mapper2(C);
C mapper3(D);

, и я буду оценивать их по списку ввода D, получая список A.

Список функций предоставляется пользователем. Это известно во время компиляции, но мне неизвестно. Как это реализовать, например, какую структуру данных следует использовать для поддержки списка функций?

Пользователь предоставляет функции с помощью API шаблона:

template <typename T>
class Mapper {
public:
    unique_ptr<Mapper<N>> map(function<N(T)>);
}

Ответы [ 3 ]

0 голосов
/ 09 мая 2020

Вот доказательство концепции, вы можете лучше адаптировать ее для своих нужд. Я определил mapper как функцию.

template <typename T>
std::vector<T> helper(std::vector<T> vec) {
  return vec;
}

template <typename T, typename Fun>
std::vector<T> helper(std::vector<T> vec, Fun fun) {
  std::vector<T> result;
  for (const auto& v : vec) {
    result.emplace_back(fun(v));
  }
  return result;
}

template <typename T, typename Fun, typename... Funs>
std::vector<T> helper(std::vector<T> vec, Fun fun, Funs... funs) {
  return helper(helper(vec, funs...), fun);
}

template <typename T, typename... Funs>
std::vector<T> mapper(std::vector<T> vec, Funs... funs) {
  return helper(vec, funs...);
}

int main() {
  auto result = mapper(
      std::vector<int>{1, 2, 3},
      [](auto v) { return v * v; },
      [](auto v) { return 2 * v; }, 
      [](auto v) { return v + 1; });

  for (const auto& v : result) {
    std::cout << v << std::endl;
  }
}

Примечание: если вам нужен другой заказ, замените

return helper(helper(vec, funs...), fun);

на:

return helper(helper(vec, fun), funs...);
0 голосов
/ 09 мая 2020

Поскольку у ваших картографов разные подписи, вам понадобится tuple для их хранения. И я не вижу причин использовать std::function, поскольку нам не нужно стирать его тип.

Моя идея довольно проста: мы храним все сопоставители в кортеже и создаем для них рекурсивный вызов. (обратите внимание, что для простоты я не беспокоюсь о пересылке. Вы можете добавить это, если хотите).

template <class... Args>
struct Mapper
{
    std::tuple<Args...> fs;

    Mapper(Args... args) : fs{args...} {}

    template <std::size_t I, class T>
    auto call(T arg)
    {
        if constexpr (I == sizeof...(Args))
            return arg;
        else
            return call<I + 1>(std::get<I>(fs)(arg));
    }

    template <class T>
    auto operator()(T arg)
    {
        return call<0>(arg);
    }
};

Пример использования:

auto test()
{
    auto mapper = Mapper{mapper3, mapper2, mapper1};

    D d{};
    A a = mapper(d);
}
0 голосов
/ 08 мая 2020

вы можете использовать std :: list типа команды, создавая функции типа команды, определенные в ссылке

http://www.vincehuston.org/dp/command.html

Подводя итоги содержания ниже:

  1. Определите командный интерфейс с помощью сигнатуры метода, например execute ().

  2. Создайте один или несколько производных классов, которые инкапсулируют некоторое подмножество следующего: a " получатель ", вызываемый метод, передаваемые аргументы.

  3. Создание экземпляра объекта Command для каждого отложенного запроса на выполнение.

  4. Передача Командный объект от создателя (он же отправитель) к вызывающему (он же получатель).

  5. вызывающий решает, когда выполнять ().

Пример прилагается:

class Giant {
public:
   Giant()       { m_id = s_next++; }
   void fee()    { cout << m_id << "-fee  "; }
   void phi()    { cout << m_id << "-phi  "; }
   void pheaux() { cout << m_id << "-pheaux  "; }
private:
   int  m_id;
   static int s_next;
};
int Giant::s_next = 0;

class Command {
public:
   typedef void (Giant::*Action)();
   Command( Giant* object, Action method ) {
      m_object = object;
      m_method = method;
   }
   void execute() {
      (m_object->*m_method)();
   }
private:
   Giant* m_object;
   Action m_method;
};

template <typename T>
class Queue {
public:
   Queue() { m_add = m_remove = 0; }
   void enque( T* c ) {
      m_array[m_add] = c;
      m_add = (m_add + 1) % SIZE;
   }
   T* deque() {
      int temp = m_remove;
      m_remove = (m_remove + 1) % SIZE;
      return m_array[temp];
   }
private:
   enum { SIZE = 8 };
   T*  m_array[SIZE];
   int m_add, m_remove;
};

int main( void ) {
   Queue que;
   Command* input[] = { new Command( new Giant, &Giant::fee ),
                        new Command( new Giant, &Giant::phi ),
                        new Command( new Giant, &Giant::pheaux ),
                        new Command( new Giant, &Giant::fee ),
                        new Command( new Giant, &Giant::phi ),
                        new Command( new Giant, &Giant::pheaux ) };

   for (int i=0; i < 6; i++)
      que.enque( input[i] );

   for (int i=0; i < 6; i++)
      que.deque()->execute();
   cout << '\n';
}

// 0-fee  1-phi  2-pheaux  3-fee  4-phi  5-pheaux
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...