2012-11-26 3 views
1

"링크 가능 속성"이라는 상대적으로 안전한 (그러나 동적 인) 효율적인 개념을 만들려고합니다. 연결 가능한 속성은 C#의 속성을 바인딩하는 기능과 비슷하며 신호/슬롯 모델과 유사합니다.C++ 링크 가능 속성

연결 가능 속성은 다른 유형의 값에 자신을 연결할 수있는 유형입니다. 값이 변경되면 모든 값이 업데이트됩니다. 여러 속성/값을 동시에 업데이트해야하는 경우에 유용합니다. 링크를 설정하면 모든 것이 처리됩니다.

  1. 다른 유형의 모든 유형에서 링크 할 수 있습니다
  2. 링크 목록이 아닌 링크 된 목록을 사용 (이론적으로,이 문제입니다). 이것은 메모리와 속도면에서 더 효율적이며이 접근법을 사용하면 실제로 이점을 얻을 수 있습니다.
  3. 변환기는 값을 한 형식에서 다른 형식으로 변환하는 데 사용됩니다 (1, 필수, 문제 포함)
  4. 게터 및 설정자처럼 작동 할 수 있습니다.

내가 어려움을 겪고있는 문제는 연결하고 모든 유형으로 변환하는 기능을 작성하는 것입니다. 다음 코드는 사소한 변경으로 작동합니다 (템플리트 체인 함수를 템플리트되지 않은 버전으로 변환하고 SetLink 함수에서 을 Chain으로 변경). 문제는 링크가 제대로 호출되지 않는다는 것입니다.

이 클래스는 거의 작동하지만 예상대로 작동하지 않습니다. 위의 변경 사항이 없으면 바인딩 함수는 호출하지 않습니다. 테스트 코드이며 올바르게 코딩되지 않았습니다. 정적 사용에 대해서는 언급하지 마십시오. 카운터는 단지 일시적인 문제입니다.) 체인과 링크 요소는 중요한 부분입니다. 체인은 단순히 속성 값을 변환하고 업데이트 한 다음 (또는 원래 값) 속성 값을 다음 항목으로 전달한다고 가정합니다. 이 속성은 원래 속성으로 돌아갈 때까지 계속되며이 경우 속성이 종료됩니다.

#include <iostream> 
#include <string> 
#include <boost/bind.hpp> 
#include <boost/function.hpp> 

using namespace std; 



static int iLCount = 1; 
template <typename T> 
class LinkableProperty 
{ 
    public: 
     std::string Name;  
     boost::function<void(T)> Link; 

     T Value; 

     template<typename F> 
     void Chain(F val) 
     { 
      Value = val; 
      std::cout << this->Name << " - " << this << ", " << &Link << ", " << val << " ! " << this->Value << " - " << "\n"; 
      if (--iLCount < 0) return; 
      if (!Link.empty()) Link(Value); 
     } 


     LinkableProperty() { Link = NULL; Value = T(); Name = "Level " + std::to_string(iLCount++); }; 

     void operator =(T value) { Value = value; } 

     template<typename F> void SetLink(LinkableProperty<F> &p) 
     {   
      Link = boost::bind(&LinkableProperty<F>::template Chain<F>, &p, _1); 
     } 

     void operator()() 
     { 
      if (!Link.empty()) Link(Value); 
     } 

}; 



int main() 
{ 

    LinkableProperty<unsigned short> L1; 
    LinkableProperty<double> L2; 

    L2.SetLink(L1); 
    L1.SetLink(L2); 

    L1 = 1; 
    L2 = 1.1; 

    L1(); 

    cout << "----------\n" << L1.Value << ", " << L2.Value << endl;  
    getchar(); 
    return 0; 
} 

답변

1

여기에서 문제가 발생할 가능성이 큽니다.

template<typename F> void SetLink(LinkableProperty<F> p) 

원본 속성의 복사본을 전달합니다. 이것을 참조 (또는 포인터)를 받아들이도록 변경하면 행운을 누릴 수 있습니다. 예를 들어 :

template<typename F> 
void SetLink(LinkableProperty<F>* p) 
{   
    Link = boost::bind(&LinkableProperty<F>::template Chain<F>, p, _1); 
} 

는 ... 예상대로

편집 일을해야 : 업데이트 전환을 통해 유형을 보존하는 방법을 보여줍니다 :

template <typename FT, typename TT> 
TT convert(FT v) 
{ 
    return v; // default implicit conversion 
} 

template<> 
double convert(unsigned short v) 
{ 
    std::cout << "us->d" << std::endl; 
    return static_cast<double>(v); 
} 

template<> 
unsigned short convert(double v) 
{ 
    std::cout << "d->us" << std::endl; 
    return static_cast<unsigned short>(v); 
} 

static int iLCount = 1; 
template <typename T> 
class LinkableProperty 
{ 
    template <typename U> 
    struct _vref 
    { 
    typedef U vt; 
    _vref(vt& v) : _ref(v) {} 
    U& _ref; 
    }; 
    public: 
     std::string Name;  
     boost::function<void(_vref<T>)> Link; 

     T Value; 

     template<typename F> 
     void Chain(F const& val) 
     { 
      Value = convert<typename F::vt, T>(val._ref); 
      std::cout << this->Name << " - " << this << ", " << &Link << ", " << val._ref << " ! " << this->Value << " - " << "\n"; 
      if (--iLCount < 0) return; 
      if (!Link.empty()) Link(Value); 
     } 


     LinkableProperty() { Link = NULL; Value = T(); Name = "Level " + std::to_string(iLCount++); }; 

     void operator =(T value) { Value = value; } 

     template<typename F> 
     void SetLink(LinkableProperty<F>* p) 
     {   
      Link = boost::bind(&LinkableProperty<F>::template Chain<_vref<T>>, p, _1); 
     } 

     void operator()() 
     { 
      if (!Link.empty()) Link(_vref<T>(Value)); 
     } 

}; 



int main() 
{ 

    LinkableProperty<unsigned short> L1; 
    LinkableProperty<double> L2; 

    L2.SetLink(&L1); 
    L1.SetLink(&L2); 

    L1 = 1; 
    L2 = 1.1; 

    L1(); 

    cout << "----------\n" << L1.Value << ", " << L2.Value << endl;  
    getchar(); 
    return 0; 
} 

주 : 일부 링크 버그가 인 업데이트가 필요한 것보다 더 많이 트리거된다는 것을 의미합니다. 다음을 확인해야합니다.

+0

감사합니다. 제가 약간의 실수를했습니다. 기본적으로 올바른 속성을 업데이트합니다. 실제 문제는 전달 된 값이 Chain 명령에서 암시 적으로 변환된다는 것입니다. 링크가 F 유형이고 T 유형이 아니어야하기 때문입니다. 물론 SetLink와 Chain 외부의 F는 알지 못합니다. 적어도 디버거는 Chain의 val이 Value와 동일한 유형임을 나타냅니다 (다른 경우). 디버거가 혼란 스러울 수도 있지만 값이 암시 적으로 변환되고 있다고 상상합니다 (가능하다면 명시 적으로 변환하려고합니다). – AbstractDissonance

+0

암시 적 변환을 피할 수 없습니다. 이는 바인딩 된 함수 실행 단계에서 발생합니다. 이것 (바인딩 메커니즘을 작성하는 것의 부족)을 둘러싼 유일한 방법은, 네이티브'Value'를 전달하는 것이 아니라 그것을 감싸고'Chain' 함수로 래퍼를 받아들이는 것입니다. 그런 다음 명시 적으로 변환하십시오 ... – Nim

+0

.. 업데이트 호출 중 암시 적 변환을 피하는 방법을 보여주기 위해 업데이트되었습니다 ... – Nim