2009-04-16 55 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