2010-05-11 7 views
2

사용자가 동일한 유형의 두 데이터 구조의 멤버를 동시에 변경할 수 있도록 허용해야합니다. 예를 들면 다음과 같습니다.C++의 "Automatic"클래스 프록시

struct Foo { int a, b; } 

Foo a1 = {1,2}, a2 = {3,4}; 
dual(a1,a2)->a = 5; 
// Now a1 = {5,2} and a2 = {5,2} 

나는 작동하는 클래스가 있으며 처음에는 a1을 변경 한 다음 a1을 a2로 복사합니다. 사용자가 모든 것에 대해 신경 쓰지 않는다

    • 복사 클래스가없는 부분 만 수정, 복사 작 :이만큼 괜찮습니다.

    이 동작을 얻을 수있는 방법이 있나요 :

    dual(a1,a2)->a = 5; 
    // Now a1 = {5,2} and a2 = {5,4} 
    

    내가 대체 문법에 오픈하고는 있지만, 간단한 유지해야하고, 내가 좋아하는 것을 방지하기 위해 싶습니다

    set_members(a1, a2, &Foo::a, 5); 
    members(a1, a2, &Foo::a) = 5; 
    

    또는 명시 적으로 지정하는 항목 &Foo::

    [편집]

    정확해야합니다. 요점은 그래프 라이브러리로 작업하는 것입니다. 라이브러리는 유향 그래프에서 작동하지만 주어진 v1과 v2의 두 꼭지점에서 가장자리 v1-> v2이면 가장자리 v2-> v1이됩니다. 그리고이 두 가장자리는 매우 자주 (항상 그런 것은 아닙니다) 동일한 속성을가집니다.

    G.edge(v1,v2)->b = 5; // Only v1->v2 is modified 
    G.arc(v1,v2)->a = 10; 
    // Now G.edge(v2,v1) is set to G.edge(v1,v2) after the modification a = 10 (i.e. b = 5 too) 
    

    을 그리고 난 단지 a이 수정되는 것을 의미하는 표기를 싶습니다 그래서 현재의 구현은 지금 할 수 있습니다.

  • +1

    단순화해야 할 필요성이 실제로 그렇게 일반적인 요구 사항입니까? 나는 그것이 당신이 성취하고자하는 것이 무엇이든지하는 더 좋은 방법이있을 것이라고 생각합니다. 실제 질문에 대해서는 좋은 구문을 허용하는 방법이 없습니다. 매크로를 사용하면 set_members (a1, a2, a, 5)를 작동시킬 수는 있지만 여러 단계에서보기 흉한 것으로 생각됩니다. –

    +0

    슬프게도! 이 질문은 직접적으로가 아니라 내 사용자의 요구 사항에서 비롯되었습니다. 첫 번째 종류 만 허용하면 보일러 플레이트 코드가 약 50 % 절약됩니다. – PierreBdR

    답변

    -1
    struct proxy { 
        struct column { 
        column(T &a, T &b); 
        column& operator=(T); 
        T &a, &b; 
        }; 
        proxy(U &A, U &B); 
        column operator[](int i) { return column(A[i], B[i]; } 
        U &A, &B; 
    }; 
    
    proxy(A, B)[0] = 5; 
    // or you could be evil, overload ",", and get this syntax 
    (A, B)[0] = 5; 
    

    또는

    을 (댓글 형식이 없기 때문에이 여기에 넣어)

    0

    편집 그래서 당신은 당신의 현재 코드이 많이 가지고 말하는 변화의 일종 :

    G.edge(v3,v4)->a = 2; 
    G.edge(v3,v4)->b = 2; 
    G.edge(v4,v5)->a = 6; 
    G.edge(v4,v5)->b = 6; 
    

    그리고 이것의 아주 조금 :

    G.edge(v5,v6)->a = 4; 
    G.edge(v5,v6)->b = 7; 
    

    귀하의 목표는 [1] 특수 사례를 덜 쉽게 구분할 수있게 만드는 것입니다 [2].

    ----- 원래의 대답은, 지금 무관 할 수있다 -----

    가능한 개선이 많이 있습니다 여기에 일반적인 생각이있다 :

    class MagicBag 
    { 
    private: 
        // you could make the whole class a template 
        // instead of hard-coding Foo.. 
        vector<Foo *> m_vec; 
    
    public: 
        // store references to the items 
        void Add(Foo *f) { m_vec->push_back(f); } 
    
        // you can do overloads instead of these setters... 
        void set_a(int val) { 
         for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i) 
          (*i)->a = val; 
        } 
    
        void set_b(int val) { 
         for (vector<Foo>::iterator i = m_vec.start(); i != m_vec.end(); ++i) 
          (*i)->b = val; 
        } 
    } 
    

    사용법 :

    Foo a1 = {1,2}, a2 = {3,4}; 
    MagicBag mb; 
    
    mb.Add(&a1); 
    mb.Add(&a2); 
    mb.set_a(5); // now a1.a = 5 and a2.a = 5 
    // etc. 
    

    이 기능은 C#과 같은 속성을 지원하는 언어에서 의미 상 더 쉽습니다.Boost.Lambda와

    mb.a = 5; 
    
    +0

    실제로, 참조를 저장하는 대신 복사본을 만드는 중입니다. – Anycorn

    +0

    고정 ... 제 생각에는 – egrunin

    +0

    문제는 각 클래스에 대해 완전히 새로운 프록시를 만들어야한다는 것입니다. 속성 당 새 메서드를 정의해야합니다. 설정. – PierreBdR

    2

    상대적으로 간단한 해결책 : 마지막 구문이 될 것이다 듀얼()와 가변 인자 템플릿을 확장

    #include <boost/lambda/lambda.hpp> 
    
    using namespace boost::lambda; 
    
    template<typename T, typename U, typename V> 
    void dual(const T& functor, U& a1, V& a2) 
    { 
        functor(a1); 
        functor(a2); 
    } 
    
    struct Foo 
    { 
        int a; 
    }; 
    
    struct Bar 
    { 
        char a; 
    }; 
    
    int main() 
    { 
        Foo a1; 
        Bar a2; 
    
        dual(_1 = 5, a1.a, a2.a); 
    } 
    

    /Boost.Preprocessor 헛소리는 독자에게 연습으로 남아 있습니다.

    1

    // 원하는 문법

    template<class T> 
    class SetPropertyProxy 
    { 
    public: 
        SetPropertyProxy(T& _v1, T& _v2) 
        : a(_v1, _v2) {} 
    
        class A_Property_Proxy 
        { 
        public: 
         A_Property_Proxy(T& _v1, T& _v2): v1(_v1), v2(_v2) {} 
         A_Property_Proxy& operator = (T::A_Property_Type val) 
         { 
          v1.a = val; 
          v2.a = val; 
          return *this; 
         } 
        private: 
         T& v1; 
         T& v2; 
        } 
        //public member "a" 
        A_Property_Proxy a; 
    }; 
    //helper function 
    template<class T> 
    SetPropertyProxy<T> dual(T& a , T& b) 
    { return SetPropertyProxy<T>(a,b); } 
    //usage 
    dual(a,b).a = 5; //calls A_Property_Proxy::operator = 
    

    그 속성 타입에 의해 매개 변수화 (이 경우, 가장자리) 속성 용기 참조 대신 특성에 대한 참조를 취하여 A_Property_Proxy 클래스를 재사용하기 더욱 향상시킬 수있다

    도착
    template<class U> 
        class Property_Proxy 
        { 
        public: 
         Property_Proxy(U& _v1prop, U& _v2prop): v1prop(_v1prop), v2prop(_v2prop) {} 
         Property_Proxy& operator = (U val) 
         { 
          v1prop = val; 
          v2prop = val; 
          return *this; 
         } 
        private: 
         U& v1prop; 
         U& v2prop; 
        } 
    
    +0

    그게 문제의 흥미로운 부분입니다. 감사. – PierreBdR

    0

    템플릿 남용을 도입함으로써 원하는 구문 대부분을 얻을 수 있습니다. 이것은 컴파일 및 작동하지만 이에 대한 보장은 없습니다. 일부 매크로를 사용할 구조체를 추가해야하며 직접 할당 대신 set_ *를 사용해야합니다.

    #include <iostream> 
    
    #define PROPERTY_MAP(ClassName) \ 
        struct hidden_Mapper {  \ 
         ClassName * m_d1;  \ 
         ClassName * m_d2;  \ 
         hidden_Mapper(Data * d1, Data * d2) : \ 
          m_d1(d1), m_d2(d2) {} 
    
    #define DECLARE_PROPERTY(name)\ 
        template <typename ValueType> \ 
        void set_##name(const ValueType & value) \ 
        { m_d1->name = value; m_d2->name = value; } \ 
    
    #define END_PROPERTY_MAP }; 
    
    
    template<typename ClassType> 
    typename ClassType::hidden_Mapper dual(ClassType & d1, ClassType & d2) 
    { 
        return typename ClassType::hidden_Mapper(&d1, &d2); 
    } 
    
    struct Data 
    { 
        int a; 
        float b; 
    
        PROPERTY_MAP(Data) 
         DECLARE_PROPERTY(a) 
         DECLARE_PROPERTY(b); 
        END_PROPERTY_MAP 
    }; 
    
    int main() 
    { 
        Data d1, d2; 
        dual(d1, d2).set_a(5); 
        dual(d1, d2).set_b(5.7); 
        std::cout << d1.a << d2.a << d1.b << d2.b <<std::endl; 
    }