2017-09-06 79 views
0

我想有一個類成員變量可以在地圖中的項目之間切換,以便修改時,地圖的內容也會被修改。使用類成員變量作爲參考

除了使用指向地圖內容的指針外,還有其他方法嗎?舊代碼只需要變量,現在新代碼需要切換。如果我更改變量類型,則需要更改使用此成員變量的所有函數。並不複雜,但是我會發現在任何地方都有它的前景是醜陋的......

參考變量不能被反彈,所以我該怎麼做到這一點?

class A 
{ 
    std::map<std::string,std::vector<int>> mMyMap; 
    std::vector<int>& mCurrentVector; 
    std::vector<int>* mCurrentVectorPointer; 
    std::vector<int> mDefaultVector; 

    void setCurrentVector(int iKey); 
    void addToCurrentVector(int iValue); 
} 


A::A(): 
mDefaultVector(std::vector<int>()) 
mCurrentVector(mDefaultVector) 
{ 
    mMyMap["key1"] = std::vector<int>(1,1); 
    mMyMap["key2"] = std::vector<int>(1,2); 
    mCurrentVectorPointer = &mMyMap[0]; 
} 

A::setCurrentVector(std::string iKey) 
{ 
    if(mMyMap.find(iKey) != mMyMap.end()) 
    { 
     mCurrentVector = mMyMap[iKey]; //can't change a reference... 
     mCurrentVectorPointer = &mMyMap[iKey]; //could use pointer, but 
    } 
} 

A::addToCurrentVector(int iValue) 
{ 
    mCurrentVector.push_back(iValue); 
    //or 
    (*mCurrentVectorPointer).push_back(iValue); 
    // 
    mCurrentVectorPointer->push_back(iValue); 
} 


void main() 
{ 
    A wClassA(); 
    wClassA.setCurrentVector("key2"); 
    wClassA.addToCurrentVector(3); 
    wClassA.setCurrentVector("key1"); 
    wClassA.addToCurrentVector(4); 
} 

mMyMap [ 「鍵1」]現在包含1,4

mMyMap [ 「KEY2」 現在包含2,3

+1

保存c urrent鍵並在add函數中使用'mMyMap [currentKey] .push_back(iValue)'。 –

+0

粉碎,這個示例代碼充滿了錯誤,它更多的是分心而不是澄清。 – user4581301

+0

只需使用向量並使用運算符 - >。 * mCurrentVectorPointer.push_back是語法錯誤!另一種解決方案是創建一個可以模擬矢量接口的vector_view,不幸的是,點運算符沒有在C++ 17中創建,實現時間比切換到指針替代方案要長。 – Oliv

回答

0

一旦被分配你不能重新綁定一個引用這意味着你只剩下使用你的其他選項,一個指針。

據我所知,你正在重構一些現有的代碼,它只使用一個單一的向量,而現在你需要一個向量圖。

您試圖通過最小的修改來實現這一點,並保持與矢量的接口相同。

一個選項將使用本地參考,從您的指針分配。

class A 
{ 
    using Vector = std::vector<int>; 
public: 
    A() 
    { 
     map_["key1"] = std::vector<int>(1,1); 
     map_["key2"] = std::vector<int>(1,2); 
     curr_vec_ = &map_["key1"]; 
    } 

    void setCurrentVector(const std::string& key) 
    { 
     if(map_.find(key) != map_.end()) 
     { 
      curr_vec_ = &map_[key]; 
     } 
    } 

    void addToCurrentVector(int val) 
    { 
     assert(curr_vec_); 
     Vector& curr_vec = *curr_vec_; // local reference 

     curr_vec.push_back(val); 

     curr_vec[0] = 2; 
     // etc 
    } 

private: 
    std::map<std::string, Vector> map_; 
    Vector* curr_vec_ = nullptr; 
} 
+0

是的,正如我提到的,我曾經想過這個想法,但是這會很快變得醜陋,並且需要很多代碼更改,即:當您需要訪問[]運算符'(* curr_vec _)[0]'而不是'curr_vec_ [ 0]'等 – Smash

+0

@Smash選項將是使用本地引用。我已經更新了我的回答 –

+0

好主意,但是代碼使用了一個向量的成員變量,所以我需要在每個函數中使用本地引用,這些變化的範圍非常相似,如果存在,我會給它一些想法沒有其他解決方案 – Smash

0

你可以寫一些包裝:

#define Return(X) noexcept(noexcept(X)) -> decltype(X) { return X; } 


template <typename U> 
class MyVectorRef 
{ 
private: 
    std::vector<U>* vec = nullptr; 
public: 
    explicit MyVectorRef(std::vector<U>& v) : vec(&v) {} 

    void reset(std::vector<U>& v) {vec = &v;} 

    // vector interface 
    auto at(std::size_t i) const Return(vec->at(i)) 
    auto at(std::size_t i) Return(vec->at(i)) 
    auto operator [](std::size_t i) const Return(vec->operator[](i)) 
    auto operator [](std::size_t i) Return(vec->operator[](i)) 

    template <typename ... Ts> auto assign(Ts&&... ts) Return(vec->assign(std::forward<Ts>(ts)...)) 
    auto assign(std::initializer_list<U> ilist) Return(vec->assign(ilist)) 
    template <typename T> auto push_back(T&& t) const Return(vec->push_back(std::forward<T>(t))) 
    template <typename T> auto emplace_back(T&& t) const Return(vec->emplace_back(std::forward<T>(t))) 

    auto begin() const Return(vec->begin()) 
    auto begin() Return(vec->begin()) 
    auto end() const Return(vec->end()) 
    auto end() Return(vec->end()) 
    auto cbegin() const Return(vec->cbegin()) 
    auto cend() const Return(vec->cend()) 
    // ... 
}; 

,然後使用它:

class A 
{ 
public: 
    A() : mCurrentVector(mDefaultVector) { 
     mMyMap["key1"] = std::vector<int>(1,1); 
     mMyMap["key2"] = std::vector<int>(1,2); 
    } 

    std::map<std::string, std::vector<int>> mMyMap; 
    std::vector<int> mDefaultVector; 
    MyVectorRef<int> mCurrentVector; 

    void setCurrentVector(std::string iKey) 
    { 
     auto it = mMyMap.find(iKey); 
     if (it != mMyMap.end()) 
     { 
      mCurrentVector.reset(it->second); 
     } 
    } 
    void addToCurrentVector(int iValue) 
    { 
     mCurrentVector.push_back(iValue); 
    } 

}; 

但我認爲這將是簡單的A只創建一個getter和直接使用一個指針:

class A 
{ 
public: 
    A() : mCurrentVector(&mDefaultVector) { 
     mMyMap["key1"] = std::vector<int>(1,1); 
     mMyMap["key2"] = std::vector<int>(1,2); 
    } 

    std::map<std::string, std::vector<int>> mMyMap; 
    std::vector<int> mDefaultVector; 
    std::vector<int>* mCurrentVector; 

    std::vector<int>& GeCurrentVector() { return *mCurrentVector; } 

    void setCurrentVector(std::string iKey) 
    { 
     auto it = mMyMap.find(iKey); 
     if (it != mMyMap.end()) 
     { 
      mCurrentVector = &it->second; 
     } 
    } 
    void addToCurrentVector(int iValue) 
    { 
     GeCurrentVector().push_back(iValue); 
    } 

}; 
+0

爲了獲得更高的透明度,請在您的宏中添加'noexcept(noexcept(X))'。 – aschepler

+0

@aschepler:已添加。 – Jarod42