2012-04-19 78 views
1

我的意思是'中间'函数是:一个正常的函子,其中一个参数可以在调用时指定。问题是我有一个动画时间线(基本上是特定帧的标量值),并且这个输出需要通过管道传入和传出要设置动画的对象中的getter/setter方法。以下是我试图一个简单的例子:C++试图创建一个'Intermediate'函子

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有其他的默认初始化参数。我不认为这会是一个问题,因为它们是默认的!但是当编译器期望指向方法的指针比我提供的更多时,它失败了。

然后我尝试使用可变参数模板参数,以便默认值可以手动放入,但落在第一个障碍,因为我不能将参数包存储为一个成员,作为参数重复应用到指针-方法。我也一直在寻找std :: function和std :: bind,我希望能够通过getter/setter方法的默认参数预设将std :: function存储为成员,并将相应的arg从调用之前的时间线。只有我找不到办法...

有没有人有任何建议来实现我的目标?或者,我的设计从根本上有缺陷,有一个更简单的方法?

回答

1

std::function将是要走的路。将仅使用std::function<Scalar(const ObjType*)>作为您的获取者,std::function<void(ObjType*, Scalar)>作为您的设置者(如果Scalar s可隐式转换为/从float s,我甚至会使用std::function<float(ObjType const*)>std::function<void(ObjType*, float)>或分别)。你可以初始化这些例如。与lambda函数:

Sy_propertyBridge(my_obj, 
    [](const MyObjType* o) -> float { return o->opacity; }, 
    [](const MyObjType* o, float f) { o->opacity=f; }) 

注意,有可能是这样做的更优雅的方式(例如,有可能是只有一个功能,可以既作为一个getter和一个setter)。

把它更进一步,你可以

  • 摆脱obj_成员变量
  • 摆脱o参数对功能的

的lambda表达式将不得不记住他们将操作的对象。因此,上述构造函数调用将变为

Sy_propertyBridge(
    []() -> float { return my_obj->opacity; }, 
    [](float f) { my_obj->opacity=f; }) 
+0

我一直在试图找到一个借口来使用lambda的!谢谢,我会放弃它,并让你知道我如何继续。 – cmannett85 2012-04-20 06:03:38

+0

美妙地工作,一个奇妙的解决方案。 – cmannett85 2012-04-21 07:53:32

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的指针数组,然后直接调用这些指针,只要它们按照您的要求操作即可。

+0

动画对象可以具有任意数量的动画属性,因此单个get/set方法不够。同样在维护级别上,使用用户指定的桥接对象将对象的动画属性与其时间线完全分离,并允许最终用户通过断开连接来禁用它们。但原则上,你没有错。 – cmannett85 2012-04-20 06:01:22