2009-04-16 31 views
7

一個const矢量成員變量我有一個類X,這是我提供的此片段:串聯C++迭代器的範圍爲在施工時間

class X { 
    public: 
    template <typename Iter> 
    X(Iter begin, Iter end) : mVec(begin, end) {} 

    private: 
    vector<Y> const mVec; 
}; 

我現在想要一個新的串聯構造函數添加到這個類,是這樣的:

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(???) { ??? } 

這樣的構造函數鏈狀兩個範圍[begin1,END1)和[begin2,END2)到MVEC。挑戰是

1)我想保留對MVEC的常量,所以其在整個十

2)其他方法我想避免,如果在所有可能的不必要的副本認爲是常數。也就是說,一個解決方案是爲具有構造一個非const臨時一個靜態方法來範圍1,插入範圍2並將其返回,然後在定義了串聯構造函數

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) 
    : mVec(concatenate(begin1, end1, begin2, end2)) { } 

但副本的所有值我相信至少有一次額外的時間。

回答

9

不錯的問題。我會嘗試實現一個特定的迭代器包裝類型,將兩個範圍變成一個範圍。東西的線路:

// compacted syntax for brevity... 
template <typename T1, typename T2> 
struct concat_iterator 
{ 
public: 
    typedef std::forward_iterator_tag iterator_category; 
    typedef typename iterator_traits<T1>::value_type value_type; 
    typedef *value_type pointer; 
    typedef &value_type reference; 

    concat_iterator(T1 b1, T1 e1, T2 b2, T2 e2) 
     : seq1(b1), seq1end(e1), seq2(b2), seq2end(e2); 
    iterator& operator++() { 
     if (seq1 != seq1end) ++seq1; 
     else ++seq2; 
     return this; 
    } 
    reference operator*() { 
     if (seq1 != seq1end) return *seq1; 
     else return *seq2; 
    } 
    pointer operator->() { 
     if (seq1 != seq1end) return &(*seq1); 
     else return &(*seq2); 
    } 
    bool operator==(concat_iterator const & rhs) { 
     return seq1==rhs.seq1 && seq1end==rhs.seq2 
      && seq2==rhs.seq2 && seq2end==rhs.seq2end; 
    } 
    bool operator!=(contact_iterator const & rhs) { 
     return !(*this == rhs); 
    } 
private: 
    T1 seq1; 
    T1 seq1end; 
    T2 seq2; 
    T2 seq2end; 
}; 

template <typename T1, typename T2> 
concat_iterator<T1,T2> concat_begin(T1 b1, T1 e1, T2 b2, T2 e2) 
{ 
    return concat_iterator<T1,T2>(b1,e1,b2,e2); 
} 
template <typename T1, typename T2> 
concat_iterator<T1,T2> concat_end(T1 b1, T1 e1, T2 b2, T2 e2) 
{ 
    return concat_iterator<T1,T2>(e1,e1,e2,e2); 
} 

現在你可以使用:

class X { 
public: 
    template <typename Iter, typename Iter2> 
    X(Iter b1, Iter e1, Iter2 b2, Iter2 e2) 
     : mVec(concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2)) 
    {} 

    private: 
    vector<Y> const mVec; 
}; 

或(我剛剛想到這一點)你不需要重新聲明構造函數。讓你的來電者使用幫手功能:

X x(concat_begin(b1,e1,b2,e2), concat_end(b1,e1,b2,e2)); 

我還沒有檢查過代碼,只是在這裏輸入了我的頭頂。它可以編譯或不能,它可以工作或不可以...但你可以把它作爲一個起點。

2

這可能是最好的下降const(爲什麼你要堅持嗎?)。

否則,你必須建立一個連接迭代器。它有相當多的代碼,詳見this thread

+0

在我的情況下,構造實例後,vector成員變量不應該改變。使它成爲const可以幫助編譯器幫助我保證。 – SCFrench 2009-04-16 17:39:37

+0

好吧,考慮到進行連接所需的代碼量,如果你保持const,那麼更有可能你的代碼會有bug。 – avakar 2009-04-16 17:53:53

+0

SCFrench,是不是已經足夠安全了X :: mvec在X被構造後不會改變? – veefu 2009-04-16 18:51:02

2

根據您的觀點,C++的最佳或最差功能之一是您可以在必要時濫用它以完成工作。在這種情況下,const_cast會是受害者:

template <typename Iter1, typename Iter2> 
X(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2) : mVec(begin1, end1) { 
    const_cast<vector<Y>&>(mVec).insert(mVec.end(), begin2, end2); 
} 

我可能有一些細節錯了,我沒有嘗試進行編譯。但它應該給你這個想法。

1

根據編譯器的優化,您的靜態方法可能不像您想象的那麼糟糕。在C++ 0x中,移動構造函數將刪除當前正在發生的任何複製。

同時使用包裝迭代器。代碼不會像avakar鏈接的那樣糟糕,因爲您只需要實現input iterator

1

1)我想保留mVec上的常量,以便它在整個X的其他方法中被認爲是常量。

  • 這是一個成員變量好奇使用的const。它藐視好設計。根據定義,建設是一個需要改變目標的過程。

  • 至於你的要求,保持對象不可修改 - 使用適當的封裝。您應該使用const - 成員函數爲您的課程的客戶公開基於您的mVec的任何功能。

2)我想避免不必要的副本,如果可能的話。也就是說,一個解決方案是有一個靜態方法,它構造一個非const臨時值到範圍1,插入範圍2並返回它,然後定義連接構造函數爲

您應該查看move-constructors和r通常的值參考(C++ 0x的承諾目標)。閱讀article