C ++尝试创建一个“中级”仿函数

时间:2012-04-19 22:09:47

标签: c++ callback functor variadic-templates

我对'中间'仿函数的意思是:一个普通仿函数,其中一个参数可以在调用时指定。问题是我有一个动画时间轴(在特定帧上基本上是标量值),并且需要在要动画的对象内输入和输出getter / setter方法。以下是我尝试的简化示例:

template < class ObjType, class Getter, class Setter, typename Scalar >
class Sy_propertyBridge : public Sy_abstractPropertyBridge
{
public:
                        Sy_propertyBridge( ObjType* object, Getter getter,
                                           Setter setter )
                            : obj_( object ), get_( getter ),
                              set_( setter ) {}
    virtual            ~Sy_propertyBridge() {}

    inline virtual float get() const
                        {
                            //  Cannot handle default arguments.
                            Scalar tmp = ( obj_->*get_ )();
                            return static_cast< float >( tmp );
                        }
    inline virtual void set( float value )
                        {
                            Scalar tmp = static_cast< Scalar >( value );
                            ( obj_->*set_ )( tmp );
                        }
private:
    ObjType*            obj_;
    Getter              get_;
    Setter              set_;
};

时间轴只保存浮点数,因此无论对象使用什么标量类型的getter / setter方法,都必须进行转换(我对浮点数进行了部分特化,取消了转换)。 ObjType是动画对象类型,GetterSetter是指向方法的指针,Scalar是Getter和Setter类型,预计会处理。

我认为这样会很好,但是编译失败了,因为一些getter / setter有其他默认初始化参数。我不认为这会是一个问题,因为它们是默认的!但是当编译器期望指针到方法的参数比我提供的更多时,它就失败了。

然后我尝试使用可变参数模板args,因此默认值可以手动输入,但是在第一个障碍下跌,因为我无法将参数包存储为成员,以重复应用为指针指向的指针方法。我一直在看std :: function和std :: bind,我希望能够将std :: function作为成员存储,并使用getter / setter方法的默认args预设 - 并从中更改相应的arg呼叫前的时间表。只有我找不到办法做到这一点......

有没有人有任何建议来实现我的目标?或者我的设计存在根本缺陷,并且有一种更简单的方法吗?

2 个答案:

答案 0 :(得分:1)

std::function将是最佳选择。只使用std::function<Scalar(const ObjType*)>作为你的吸气者,std::function<void(ObjType*, Scalar)>作为你的设定者(如果Scalar可隐式转换为/ float s,我甚至会使用{{1} }和std::function<float(ObjType const*)>,resp。)。你可以初始化这些例如。 lambda函数:

std::function<void(ObjType*, float)>

请注意,可能有更优雅的方法(例如,可能只有一个函数既可以作为getter又可以作为setter)。

更进一步,你可以

  • 摆脱Sy_propertyBridge(my_obj, [](const MyObjType* o) -> float { return o->opacity; }, [](const MyObjType* o, float f) { o->opacity=f; }) 成员变量
  • 删除函数的obj_参数

然后lambdas必须记住他们将要操作的对象。所以上面的构造函数调用将成为

o

答案 1 :(得分:0)

根据我的理解,您正在尝试使用“get”和“set”方法,这些方法因您在此处传递的课程而异?如果是这样,我认为您应该尝试在“ObjType”对象上使用纯虚基类,然后在您传入的类中实现它。在C#/ Java术语中,一个接口。

基本上这个:

class IGetSetter
{
    virtual float get() const = 0;
    virtual void set(float) = 0;    
}

class ObjType1 : public IGetSetter
{
    virtual float get() const
    {
        // Implementation
    }

    virtual void set(float a)
    {
        // Implementation
    }
}

class ObjType2 : public IGetSetter
{
    virtual float get() const
    {
        // Implementation
    }

    virtual void set(float a)
    {
        // Implementation
    }
}

然后你的班级成为:

template < typename Scalar >
class Sy_propertyBridge : public Sy_abstractPropertyBridge
{
public:
    Sy_propertyBridge( IGetSetter* object)
        : obj_( object ) {}
    virtual ~Sy_propertyBridge() {}

    inline virtual float get() const
    {
        Scalar tmp = obj_->get();  // Uses polymorphism to find the right method
        return static_cast< float >( tmp );
    }
                        }
    inline virtual void set( float value )
    {
        Scalar tmp = static_cast< Scalar >( value );
        obj_->set( tmp );  // Uses polymorphism to find the right method
    }
private:
    ObjType* obj_;
};

但实际上,可能有一种完全削减Sy_propertyBridge类的直接方法。只需存储一个指向IGetSetter的指针数组,然后直接调用它们,如果它们符合你的要求。