C++ 如何编写一个类来接受函数指针和/或函子,就像智能指针接受自定义删除器一样?

C++ 如何编写一个类来接受函数指针和/或函子,就像智能指针接受自定义删除器一样?,c++,boost,function-pointers,functor,tr1,C++,Boost,Function Pointers,Functor,Tr1,我试图编写一个类,该类接受一个函数指针和/或一个函子,以后由该类作为用户。 为了更好地说明我想做什么: 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_p

我试图编写一个类,该类接受一个函数指针和/或一个函子,以后由该类作为用户。 为了更好地说明我想做什么:

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;
    }
  }
};
模板类持有者{
私人:
T*m_ptr;
m_func;
公众:
持有者(T*ptr):m_ptr(ptr),m_func(空){
}
持有人(T*ptr,func):m_ptr(ptr),m_func(func){
}
~Holder(){
if(m_func){
m_func(m_ptr);
}否则{
删除m_ptr;
}
}
};
考虑到我想处理这种类型的对象:

class MyClass {
public:
  void describe() {
    cout << "Bla bla bla ...";
  }
};
class-MyClass{
公众:
void descripe(){

cout一个明显的解决方案是使用
boost::function
std::function
。但是,如果希望避免这些对象增加的开销,可以让
Holder
接受可调用的模板参数:

template <typename T, class F> 
class Holder 
{
private:
  T *m_ptr;
  F m_func;
//...

答案是:类型擦除

实现并不是那么简单,我建议稍微阅读一下类型擦除(就像我刚才做的那样!)

首先,您需要创建类型擦除设备:

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

希望它对其他人有用。

您可以使用
boost::function
,请参见此处示例:c++11和
MyClassFunctor()中还有
std::function
没有做你认为它能做的事。丢失参数。@g-makulik没有很好的理由这样做,这会使代码变得不必要的复杂-想象一下,如果每次声明智能指针时,你都必须指定另一个模板参数。boost::函数和C++11 std::函数帮助很大。但是,我正在考虑这样做这在普通的C++03中是可能的吗?这似乎很有希望。我想知道boost如何在没有辅助函数的情况下使用C++03实现这一点。你有什么线索吗?@Marcus如果你的意思是
shared\u ptr
如何接受自定义的删除器,那就是它如何做到的。那里的“辅助函数”有一个参数化的构造函数(比如
template shared\u ptr(Y*p,D D)
)。请记住,扣除参数类型的唯一方法是使用[member-]函数模板。正是Igor,但是您需要使用类型擦除才能同时使用函数指针和函子。请检查我发布的解决方案。@Marcus不,您没有。类型擦除实际上是一个非模板对象(未被可调用类型参数化)这将允许存储任何可调用的,因此它实际上是
std::function
。但是如果您对这样的开销没问题,只需使用
std::function
,就无需重新设计。OTOH,使用模板解决方案,您没有这样的开销(但还有其他已知的权衡)理解Igor。STD的问题是:函数是C++ 11,不是吗?我现在试图避免C++ 11,因为大多数时候我不为PC编程,而是嵌入C++。即使是强硬的,你也是对的。谢谢你的帮助。
template <typename T, class F> 
class Holder 
{
private:
  T *m_ptr;
  F m_func;
//...
// 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);
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); }
};
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" ...