2012-04-19 3 views
1

'중간 펑터'가 의미하는 것은 : 일반적인 펑터로서, 인수 중 하나를 호출 시간에 지정할 수 있습니다. 문제는 필자가 애니메이션 타임 라인 (특정 프레임에서 본질적으로 스칼라 값)을 가지고 있으며이 출력은 애니메이션을 생성 할 객체 내에서 getter/setter 메서드로 /에서 파이프되어야한다는 것입니다. 여기에 내가 시도하고 있었는지의 간단한 예는 다음과 같습니다C++ '중급'펑터를 만들려고 시도합니다.

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

타임 라인은 수레를 보유하고, 그래서 어떤 스칼라가 나는 수레에 대한 부분 전문성을 가지고 (게터/세터 방법은, 주조되어야의의 객체가 사용하는 입력이 캐스트와 함께하지 않습니다.) ObjType은 애니메이션 객체 유형이고 GetterSetter은 메소드에 대한 포인터이며 Scalar은 Getter 및 Setter 유형이며 처리 할 것으로 예상됩니다.

나는 괜찮을 거라 생각했지만 일부 getter/setter가 다른 default-initialised 인수를 가지고 있기 때문에 컴파일이 실패했다. 나는 이것이 문제가 될 것이라고 생각하지 않았다. 그러나 컴파일러가 포인터보다 메서드에 대한 인수가 예상보다 많아 졌을 때 실패했습니다.

가변 변수 템플릿 args를 사용하여 기본 값을 직접 입력 할 수 있었지만 포인터가있는 args로 반복적으로 적용될 멤버로 매개 변수 팩을 저장할 수 없으므로 첫 번째 장애물에 빠졌습니다. -행동 양식. std :: function과 std :: bind를 살펴 봤는데 getter/setter 메서드의 기본 args 사전 설정과 함께 멤버로 std :: function을 저장할 수 있기를 바랬습니다. 전화하기 바로 전에 타임 라인. 오직 내가 할 수있는 방법을 찾을 수 없습니다 ...

누구를위한 목표를 달성하기 위해 어떤 제안이 있습니까? 또는 내 디자인에 근본적인 결함이 있으며 쉬운 접근 방법이 있습니까?

답변

1

std::function 가야 할 길입니다. getter로 std::function<Scalar(const ObjType*)>을 사용하고 Scalar을 암시 적으로 float으로 변환 할 수있는 경우 std::function<float(ObjType const*)>std::function<void(ObjType*, float)> (resp.)을 사용하기도합니다. 설정자로 std::function<void(ObjType*, Scalar)>을 사용합니다. 예를 들어 초기화 할 수 있습니다. 람다 기능 :이 일을 더 우아한 방법이 될 수 있음을

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

주 (. 예 게터와 세터로 모두를 제공 할 수 하나의 기능이있을 수 있습니다).

, 당신은

  • 이 기능에 o 매개 변수를 없애 obj_ 멤버 변수를 제거 얻을 수있는 더욱를 촬영

람다는 다음을 기억해야 할 것 그들이 조작 할 객체. 따라서 위의 생성자 호출은

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

나는 람다를 사용하는 핑계를 찾으려고 노력해 왔습니다! 고마워, 나는 그것을 줄 것이고, 내가 어떻게 일어나는지 알려줄 것이다. – cmannett85

+0

아름답게 작동하며 환상적인 솔루션입니다. – cmannett85

0

내가 이해하는 것으로부터, 여기에 전달하는 클래스마다 다른 "get"및 "set"메서드를 사용하려고합니까? 그렇다면, 당신은 당신의 "ObjType"객체에 순전히 가상 기본 클래스를 사용하려고 시도해야한다고 생각합니다. 그리고 나서 당신이 전달하는 클래스에서 그것을 구현해야합니다. C#/Java 용어로, 인터페이스.

기본적으로이 :

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 클래스이라고 전했다의 간단한 방법이있다 :

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

그런 다음 클래스가된다

. IGetSetter에 대한 포인터 배열을 저장 한 다음 원하는대로 직접 포인터를 호출하십시오.

+0

이 될 수 있습니다. 애니메이션 가능 객체는 임의의 양의 애니메이션 가능 속성을 가질 수 있으므로 단일 가져 오기/설정 방법이 충분하지 않습니다. 또한 유지 관리 수준에서 사용자 지정 브리지 객체를 사용하면 타임 라인에서 객체의 애니메이션 가능 속성을 완전히 분리 할 수 ​​있으며 최종 사용자는 연결을 끊어 비활성화 할 수 있습니다. 그러나 원칙적으로, 당신은 틀리지 않습니다. – cmannett85

관련 문제