2010-05-11 46 views
2

我需要允許用戶同時更改兩個相同類型數據結構的成員。例如:C++中的「自動」類代理

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)有效,但我認爲這在許多層面上都很難看。 – 2010-05-11 03:18:54

+0

不幸的是!這個問題來自我的用戶的要求,而不是直接來自我的要求。只允許第一種節省大約50%的鍋爐代碼。 – PierreBdR 2010-05-11 08:16:29

回答

-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#)中,這在語義上更容易。還有最後的語法是:

mb.a = 5; 
+0

其實,你正在複製,而不是存儲參考 – Anycorn 2010-05-11 04:24:01

+0

固定,我認爲... – egrunin 2010-05-11 04:36:06

+0

這裏的問題是,你需要爲每個類做一個全新的代理...並且你需要爲每個屬性定義一個新的方法設置。 – PierreBdR 2010-05-11 09:25:13

2

相對簡單的解決方案與Boost.Lambda:

#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 2010-05-15 18:29:07

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