2010-11-01 4 views
0

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

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

int myLibFunction(void* data, size_t data_size);

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

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); 
} 

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

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

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

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

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

+0

Можете ли вы использовать синтаксически действующий код в примере? – 2010-11-01 12:13:09

+0

Полиморфизм, будь то на уровне языка или его собственная ручная реализация, является решением здесь (наряду с контейнером (возможно, умных) указателей). Я бы приобрел свою собственную биту в крикет, чтобы отбить эти атаки. –

+0

Спасибо Оли. Фолиморфизм, как и в случае с Future1, Future2, полученный от Future, является моим текущим резервом, хотя это сделает меня непопулярным на работе. Однако из-за количества функций это может вызвать большое количество классов. Считаете ли вы, что это единственное решение? Извините, Роджер, я думал, что псевдокод сделает мое намерение ясным. – Iain

ответ

3

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

class Future {}; 

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

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

+0

Кажется, это трюк. Спасибо Лу и Оли. Кажется, это так очевидно, я вижу это. Я думаю, проблема в том, что я пытался применить полиморфизм к T. Спасибо! – Iain

0

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

#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; 
} 

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

Смежные вопросы