Сохранение функторов как переменных
Я работаю над классом управления ресурсами и хочу, чтобы пользователь предоставил функтор для метода "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 имеет переопределения конструктора, которые позволяют пользователю включать пользовательское освобождение (и пользовательский распределитель, если это необходимо). Этого может быть достаточно для того, что вам нужно (это разработано с учетом этого, если я правильно читаю ваш вариант использования).