Сохранение функторов как переменных

Я работаю над классом управления ресурсами и хочу, чтобы пользователь предоставил функтор для метода "ReleaseResource" как часть конструктора менеджера ресурсов. Оттуда, когда запрашивается ресурс, функтор будет предоставлен в качестве средства удаления для shared_ptr, который я буду возвращать, чтобы соответствующий метод был вызван, когда ресурс больше не используется.

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

template<class MyFunctor> MyMethod(MyFunctor f) {
    f();
}

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

Кто-нибудь может указать мне правильное направление здесь?

3 ответа

Решение
template<class MyFunctor> MyMethod(MyFunctor f) {
    boost::function<void()> g = f;
    g();
}

Тип, который вы передаете boost::function это тип функции. Например, int(bool, char) это тип функции, возвращающей int и принимающей bool и char. Тем не менее, если вы хотите создать shared_ptr сразу, вам не нужно где-то хранить функтор (boost::function требует new оператор для этого, хотя для очень маленьких функторов, он будет использовать специальные приемы, чтобы использовать только выделение стека (небольшая оптимизация буфера)):

template<class MyFunctor> MyMethod(MyFunctor f) {
    boost::shared_ptr<T> ptr(new T, f);
}

boost:: function является частью tr1 и будет частью следующего официального стандарта C++. Пример:

struct Manager {
    template<typename Deleter>
    Manager(Deleter d) 
        :deleter(d) {

    }

    boost::shared_ptr<Resource> allocate() {
        ...
        return boost::shared_ptr<Resource>(resource, deleter);
    }

private:
    boost::function<void(Resource *)> deleter;
};

Есть два способа, оба из которых сводятся к шаблонированию класса.

template <MyFunctor>
class MyClass
{
   MyFunctor   func;
  public:
    MyClass(MyFunctor f) :func(f)
    { }


    MyMethod() 
   {
       func();
   }
}

Это потребует от вас знать тип функтора. Чтобы избежать этого, мы можем использовать фабрику:

 template<MyFunctor>
 MyClass<MyFunctor>  MakeFunctorClass(MyFunctor f)
 {     
     return MyClass<MyFunctor>(f);       
 }

С другой стороны, поскольку, по всей вероятности, большая часть сигнатуры функтора будет одинаковой с изменением только небольшой части, мы могли бы использовать это:

template <MyType>
class MyClass
{
   typedef std::binary_function<MyType, MyType, bool>  MyFunctor;
   MyFunctor func;
  public:


    MyMethod(MyFunctor f) 
   {
       func = f;
       func();
   }
}

Это делает использование немного проще:

 bool AreEqual(int, int); 
 MyClass<int> myc;
 myc.MyMethod(AreEqual);

дорогим из более сложного определения (т. е. я не гарантирую, что определение типа binary_function, которое я дал, будет работать)

Не уверен, что это поможет, но имейте в виду, что boost::shared_ptr имеет переопределения конструктора, которые позволяют пользователю включать пользовательское освобождение (и пользовательский распределитель, если это необходимо). Этого может быть достаточно для того, что вам нужно (это разработано с учетом этого, если я правильно читаю ваш вариант использования).

Другие вопросы по тегам