我正在尝试编写一个接受函数指针和/或函数的类,以便稍后由该类使用。 为了更好地说明我想做的事情:
template <typename T> class Holder {
private:
T *m_ptr;
<something> m_func;
public:
Holder(T *ptr) : m_ptr(ptr), m_func(NULL) {
}
Holder(T *ptr, <something> func) : m_ptr(ptr), m_func(func) {
}
~Holder() {
if (m_func) {
m_func(m_ptr);
} else {
delete m_ptr;
}
}
};
考虑到我想处理这种类型的对象:
class MyClass {
public:
void describe() {
cout << "Bla bla bla ...";
}
};
然后我可以这样使用它:
class MyClassFunctor {
public:
void operator()(MyClass *ptr) const {
cout << "Deleting ptr using functor: ";
ptr->describe();
cout << endl;
delete ptr;
}
};
int main() {
MyClass *myclass = new MyClass();
MyClassFunctor functor();
{
Holder<MyClass> holder(myClass, functor);
}
cout << "I'm out of context now!" << endl;
}
AND(不是或)这样:
void myClassDeleter(MyClass *ptr) {
cout << "Deleting ptr using function pointer: ";
ptr->describe();
cout << endl;
delete ptr;
}
int main() {
MyClass *myclass = new MyClass();
{
Holder<MyClass> holder(myClass, &myClassDeleter);
}
cout << "I'm out of context now!" << endl;
}
注意我希望能够使用这两种方法:Functors和函数指针。
我认为这是可能的,因为这是Boost :: shared ptr和tr1 :: shared_ptr所做的。 我试着深入研究Boost :: shared_ptr代码,但我真的不明白他们是怎么做的。
如果我的代码错误或似乎天真,我很抱歉。我试着尽可能简洁地解释这个问题,所以代码的正确性不是我的主要关注点(我意识到这很重要)。
注意我甚至不考虑从头开始重写智能指针类。这是不可能的,因为我知道这不是一个明智的选择。 我很想知道如何做到这一点,所以我可以将这个机制用于其他目的。智能指针只是我记忆中最简单的用法。
目前,我想避免使用boost和C ++ 11。可以使用普通的c ++ 03吗?
非常感谢你的时间。
答案 0 :(得分:1)
答案是:输入Erasure。
实现并不那么简单,我建议稍微阅读一下Type Erasure(正如我刚才所做的那样!)。
首先,您需要创建Type Erased设备:
class ActionBase {
public:
virtual ~ActionBase() { }
virtual bool DoIt() = 0;
};
template<typename P>
class ActionP : public ActionBase {
private:
P *ptr;
public:
ActionP(P *p) : ptr(p) { }
virtual bool DoIt() {
cout << "Standard action (nothing to do)..." << endl;
return true;
}
};
template<typename P, class A>
class ActionPA : public ActionBase {
private:
P *ptr;
A action;
public:
ActionPA(P *p, A & a ) : ptr(p), action(a) { }
virtual bool DoIt() { return action(ptr); }
};
然后你可以声明Holder类:
template<typename T>
class Holder {
private:
// Avoid object copy and assignment.
Holder(const Holder<T> &rhs);
Holder<T>& operator=(const Holder<T> &rhs);
protected:
T* ptr;
ActionBase *action;
public:
template<typename U> Holder(U *ptr) : ptr(ptr), action(new ActionP<U>(ptr)) { }
template<typename U, class A> Holder(U* p, A a) : ptr(p), action(new ActionPA<U, A>(p, a)) { }
virtual ~Holder() { delete ptr; delete action; }
bool DoAction() {
return this->action->DoIt();
}
};
然后你可以使用它传递函数指针,仿函数,甚至没有:
template<typename T>
class ActionFunctor {
public:
bool operator()(T* instance) const {
cout << "Action operator..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get());
return true;
}
};
template<typename T>
bool ActionFunc(T* instance) {
cout << "Action function..." << endl;
// Simple operation: set the value to 3 times the original value (works for int and string!!)
instance->Set(instance->Get() + instance->Get() + instance->Get());
return true;
}
int main() {
{
cout << "First test:" << endl;
ActionFunctor<X> actionX;
Holder<X> x1(new X(1), &ActionFunc<X>);
Holder<X> x2(new X(10), actionX);
Holder<X> x3(new X(100));
x1.DoAction();
x2.DoAction();
x3.DoAction();
}
{
cout << "Second test:" << endl;
ActionFunctor<Y> actionY;
Holder<Y> y1(new Y("A"), &ActionFunc<Y>);
Holder<Y> y2(new Y("BB"), actionY);
Holder<Y> y3(new Y("CCC"));
y1.DoAction();
y2.DoAction();
y3.DoAction();
}
return 0;
}
这是输出:
First test:
X constructor: 1
X constructor: 10
X constructor: 100
Action function...
Action operator...
Standard action (nothing to do)...
X desstructor: 100
X desstructor: 20
X desstructor: 3
Second test:
Y constructor: "A"
Y constructor: "BB"
Y constructor: "CCC"
Action function...
Action operator...
Standard action (nothing to do)...
Y destructor: "CCC" ...
Y destructor: "BBBB" ...
Y destructor: "AAA" ...
希望它对其他人有用。
答案 1 :(得分:0)
一个明显的解决方案是使用boost::function
或std::function
。但是,如果要避免这些对象添加的开销,可以使Holder
接受 Callable 作为模板参数:
template <typename T, class F>
class Holder
{
private:
T *m_ptr;
F m_func;
//...
当然,你必须制作一个帮助函数来扣除 Callable 的实际类型:
// depending on the nature of your functors, consider passing by const &
template<typename T, class F>
Holder<T, F> make_holder(T *t, F f)
{
return Holder<T, F>(t, f);
}
像这样使用:
auto holder = make_holder(myClass, &myClassDeleter);
// or:
auto holder = make_holder(myClass, functor);