Контейнеры общего будущего / Обещания - PullRequest
0 голосов
/ 01 ноября 2010

Мы пытаемся создать компонент библиотеки, который будет выполнять асинхронные вызовы.По разным причинам для этого необходим интерфейс, подобный C, поэтому мы предоставляем большой набор статических функций в качестве интерфейса к библиотеке.

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

int myLibFunction(void* data, size_t data_size);

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

Future<T> {
  T m_data;
}

static int myLibDoJob1(Future<Func1Data>& data);
static int myLibDoJob2(Future<Func2Data>& data);

main()
{
   Func1Data m_data;
   Func2Data m_data2;
   Future<Func1Data> future1(m_data);
   Future<Func2Data> future2(m_data2);
   int ret=0;

   ret = myLibDoJob1(future1);
   ret = myLibDoJob2(future2);
}

Это довольно чистый интерфейс, и интерфейс обеспечивает безопасность типов во время компиляции.Однако проблема у меня заключается в том, что я создаю очередь заданий для внутреннего выполнения.Однако из-за того, что Futures имеют разные размеры, я не могу создать из них очередь std: я надеялся, что смогу создать std :: queue с заданием Job, содержащим Future *, однако это недопустимо.

Я также пытался заставить Job содержать Future, где все классы данных также являются производными от ParentData, но безрезультатно.

Проблема очень похожа на проблему с контейнерами умных указателей.Из-за специфики команды, в которой я работаю, я не смогу выставить какие-либо дополнительные объекты за пределами библиотеки, и меня будут преследовать крикетной битой, если я сделаю Future полиморфным.

Важно, чтобы код на стороне пользователя в библиотеке контролировал, где на самом деле находятся данные.

С уважением, Iain

Ответы [ 2 ]

3 голосов
/ 01 ноября 2010

Либо вы будете использовать C ++ для полиморфизма, либо вы переопределите полиморфизм с помощью void*.Самый простой способ решить вашу проблему - дать Future<T> базовый класс, который не зависит от T. Обычно я делаю это так:

class Future {};

template<class T>
class FutureOf : public Future {};

Затем вы можете создавать контейнеры из Future*и иметь некоторую безопасность типов.

0 голосов
/ 01 ноября 2010

Не совсем понятно, что вы пытаетесь сделать.Однако, если я вас правильно понимаю, у вас есть куча унаследованных функций, и вы пытаетесь обернуть каждую из них в (шаблонный) класс и предоставить ему данные для конкретного типа.Может ли что-то вроде следующего сделать то, что вы хотите?

#include <iostream>
#include <list>

class AbstractFuture
{
public:
    virtual int compute() const = 0;
};

// Encapsulates function and data
template <typename F, typename T>
class Future : public AbstractFuture
{
public:
    Future(F func, T x) : func_(func), x_(x) {}
    virtual int compute() const { return func_(x_); };
private:
    const F func_;
    const T x_;
};

// Helper function template, to save all the explicit <> nonsense
// you'd need otherwise
template <typename F, typename T>
AbstractFuture *createFuture(F func, T x) { return new Future<F,T>(func, x); }

// Some data types
typedef float Func1Data;
typedef double Func2Data;

// Dummy function implementations
static int myLibDoJob1(const Func1Data& data)     { return 5; }
static int myLibDoJob2(const Func2Data& data)     { return 7; }


int main()
{
    // Data for each Future
    Func1Data x1 = 0;
    Func2Data x2 = 0;

    // Create some Futures (note, the function template makes this type-safe)
    AbstractFuture *p1 = createFuture(myLibDoJob1, x1);
    AbstractFuture *p2 = createFuture(myLibDoJob2, x2);

    // Put into a container (of pointers to base class)
    std::list<AbstractFuture *> futures;
    futures.push_back(p1);
    futures.push_back(p2);

    // Demonstrate polymorphism works
    for (std::list<AbstractFuture *>::const_iterator it = futures.begin();
         it != futures.end(); ++it)
    {
        std::cout << (*it)->compute() << std::endl;
    }

    delete p1;
    delete p2;

    return 0;
}

Это может быть сделано более аккуратно с помощью умных указателей, но идея должна сохраняться.

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