如何在数组或向量中使用不同的functoid

时间:2015-04-14 05:34:14

标签: c++ functor c++98

我已经编写了一小段代码,我可以使用mem_fun模板在一个functoid中调用setter和getter函数。

我现在想在类层次结构之上使用这种方法,其中每个类都可能具有getter和setter,它可以在向量或数组中注册为pair,以便能够在需要时调用getter和setter。 GUIObject和GUICompositeObject是所描述的类层次结构中的示例类。 不幸的是,对象的bound_mem_fun_t有不同的类型,这就是我不知道如何将它们集成到指向函子的指针数组/向量中的原因。

在c ++ 11中我会使用std :: function。有没有办法在c ++ 98中模拟这个?

因为我们的编译器只支持c ++ 98,所以我不能使用c ++ 11或c ++ 14的新功能。也不允许提升。

#include <functional>

class GUIObject
{
    int m_Alpha;
public:
    void SetAlpha(int a) { m_Alpha = a;};
    int GetAlpha() {return m_Alpha;};
};


class GUICompositeObject: public GUIObject
{
    int m_NumOfChilds;
public:
    void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
    int GetNumOfChilds() {return m_NumOfChilds;};
};

template<typename T>
struct bound_mem_fun_t 
{ 
    bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
            m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
    int operator()() { return m_GetFunc(obj); } ;
    void operator()(int i) { m_SetFunc(obj, i); } ;
    std::mem_fun_t<int, T> m_GetFunc; 
    std::mem_fun1_t<void, T, int> m_SetFunc; 
    T* obj; 
};


int main()
{
    GUIObject kGUIObject;
    GUICompositeObject kCompObj;

    bound_mem_fun_t<GUIObject> GUIObjectFunc(std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject);
    GUIObjectFunc(17);
    int ii = GUIObjectFunc();

    bound_mem_fun_t<GUICompositeObject> GUICompObjectFunc(std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj);
    GUICompObjectFunc(17);
    int iChilds = GUICompObjectFunc();

    return 0;
}

这是@filmors回答后的完整解决方案:

#include <functional>
#include <vector>
#include <iostream>

class GUIObject
{
    int m_Alpha;
public:
    void SetAlpha(int a) { m_Alpha = a;};
    int GetAlpha() {return m_Alpha;};
};


class GUICompositeObject: public GUIObject
{
    int m_NumOfChilds;
public:
    void SetNumOfChilds(int NumOfChilds) { m_NumOfChilds = NumOfChilds;};
    int GetNumOfChilds() {return m_NumOfChilds;};
};

struct bound_mem_fun_base 
{
    virtual int operator()() =0;
    virtual void operator()(int) =0;
};

template<typename T>
struct bound_mem_fun_t : public bound_mem_fun_base
{ 
    bound_mem_fun_t(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o) :
            m_GetFunc(GetFunc), m_SetFunc(SetFunc), obj(o) { } ;
    virtual int operator()() { return m_GetFunc(obj); } ;
    virtual void operator()(int i) { m_SetFunc(obj, i); } ;
    std::mem_fun_t<int, T> m_GetFunc; 
    std::mem_fun1_t<void, T, int> m_SetFunc; 
    T* obj; 
};

template<typename T> bound_mem_fun_t<T>* make_setter(std::mem_fun_t<int, T> GetFunc, std::mem_fun1_t<void, T, int> SetFunc, T* o)
{
    return new bound_mem_fun_t<T> (GetFunc, SetFunc, o);
}

int main()
{
    GUIObject kGUIObject;
    GUICompositeObject kCompObj;

    std::vector<bound_mem_fun_base*> kBoundVector;

    kBoundVector.push_back(new bound_mem_fun_t<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
    kBoundVector.push_back(new bound_mem_fun_t<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));
    kBoundVector.push_back(make_setter<GUIObject> (std::mem_fun(&GUIObject::GetAlpha), std::mem_fun(&GUIObject::SetAlpha), &kGUIObject));
    kBoundVector.push_back(make_setter<GUICompositeObject> (std::mem_fun(&GUICompositeObject::GetNumOfChilds), std::mem_fun(&GUICompositeObject::SetNumOfChilds), &kCompObj));

    for (int i = 0; i < 4 ; i++)
    {
        (*kBoundVector[i])(i*10);
        int res = (*kBoundVector[i])();
        std::cout << "Getter result " << res << "\n";
    }

    return 0;
}

不幸的是,make_setter函数并没有真正缩短仿函数的创建时间。任何想法都会受到欢迎。

2 个答案:

答案 0 :(得分:1)

只需给你的bound_mem_fun_t<T>一个公共基类并使用动态调度来解决你的问题:

struct bound_mem_fun_base {
    virtual int operator()() = 0;
    virtual void operator()(int) = 0;
};

template <typename T>
struct bound_mem_fun_t : bound_mem_fun_t ...

然后,您可以在向量中保留指向bound_mem_fun_base的指针,并将元素称为(*v[0])()

此外,TR1确实包含std::tr1::function,可用吗?

答案 1 :(得分:0)

首先从c ++ 11开始对std :: function进行评论:这不会解决你的问题,因为你需要一个已经有界的函数指针。必须将此指针绑定到您的对象。我相信你需要的是std :: bind的自己的实现。

我开始只是一个非常!小型Binder课程,有望成为您需求的起点。如果您需要在较旧的c ++版本中使用模板参数列表,请查看lokihttp://loki-lib.sourceforge.net/

作为一个提示,我可以举一个简短的例子来说明我的所作所为:

class A
{   
    private:
        int val;
    public:
        A(int i): val(i) {}  
        void Do(int i) { std::cout << "A " << val<< " " << i << std::endl; }
};  

class B
{   
    private:
        int val;
    public:
        B(int i): val(i){}
        void Go(int i) { std::cout << "B " << val << " " << i << std::endl; }
};  

class Base
{   
    public:
        virtual void operator()(int i)=0; 
};  

template <typename T>
class Binder: public Base
{   
    void (T::*fnct)(int);
    T* obj;

    public:
    Binder( void(T::*_fnct)(int), T*_obj):fnct(_fnct),obj(_obj){}  
    void operator()(int i)
    {   
        (obj->*fnct)(i);
    }   

};  

int main()
{   
    A a(100);
    B b(200);

    // c++11 usage for this example
    //std::function<void(int)> af=  std::bind( &A::Do, &a, std::placeholders::_1);
    //af(1);

    // hand crafted solution
    Base* actions[2];

    actions[0]= new Binder<A>( &A::Do, &a);
    actions[1]= new Binder<B>( &B::Go, &b);

    actions[0]->operator()(55);
    actions[1]->operator()(77);

}