1

我所说的“中间”函子的意思是:一个普通函子,其中一个参数可以在调用时指定。问题是我有一个动画时间线(本质上是特定帧的标量值),并且它的输出需要通过管道传输到要设置动画的对象中的 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是动画对象类型,Getter并且Setter是指向方法的指针,并且Scalar是 Getter 和 Setter 类型并期望处理。

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

然后我尝试使用可变参数模板 args,以便可以手动输入默认值,但由于我无法将参数包存储为成员,以便作为 args 重复应用于指向方法的指针,因此我遇到了第一个障碍。我也一直在研究 std::function 和 std::bind,我希望能够将 std::function 存储为具有 getter/setter 方法的默认 args 预设的成员 - 并从就在调用之前的时间线。只是我找不到办法做到这一点......

有没有人有任何建议来实现我的目标?还是我的设计存在根本缺陷并且有更简单的方法?

4

2 回答 2

1

std::function将是要走的路。将只std::function<Scalar(const ObjType*)>用作您的 getter,std::function<void(ObjType*, Scalar)>用作您的 setter(如果Scalars 可以隐式转换为/从floats,我什至会使用std::function<float(ObjType const*)>and std::function<void(ObjType*, float)>,resp。)。您可以初始化这些,例如。使用 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; })
于 2012-04-19T22:38:06.407 回答
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然后在它们执行您想要的操作时直接调用它们。

于 2012-04-19T22:36:40.797 回答