从 2 个向量的串联构造一个向量

Construction a vector from the concatenation of 2 vectors

本文关键字:向量 一个      更新时间:2023-10-16

有没有办法将vector构造为 2 vector s 的串联(除了创建辅助函数?

例如:

const vector<int> first = {13};
const vector<int> second = {42};
const vector<int> concatenation = first + second;

我知道vector没有string这样的加法运算符,但这就是我想要的行为。这样concatenation将包含:13和42。

我知道我可以像这样初始化concatenation,但它阻止我进行concatenation const

vector<int> concatenation = first;
first.insert(concatenation.end(), second.cbegin(), second.cend()); 

不,如果你要求,这是不可能的

  • 未定义帮助程序函数,并且
  • 生成的向量可以声明为 const
template<typename T>
std::vector<T> operator+(const std::vector<T>& v1, const std::vector<T>& v2){
    std::vector<T> vr(std::begin(v1), std::end(v1));
    vr.insert(std::end(vr), std::begin(v2), std::end(v2));
    return vr;
}

这确实需要一个辅助"函数",但至少它允许您将其用作

const vector<int> concatenation = first + second;

我认为你必须编写一个帮助函数。 我会把它写成:

std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
    auto result = lhs;
    std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
    return result;
}

调用它为:

    const auto concatenation = concatenate(first, second);

如果向量可能非常大(或包含复制成本高昂的元素),则可能需要先执行reserve以保存重新分配:

std::vector<int> concatenate(const std::vector<int>& lhs, const std::vector<int>& rhs)
{
    std::vector<int> result;
    result.reserve( lhs.size() + rhs.size() );
    std::copy( lhs.begin(), lhs.end(), std::back_inserter(result) );
    std::copy( rhs.begin(), rhs.end(), std::back_inserter(result) );
    return result;
}

(就个人而言,如果有证据表明这是一个瓶颈,我只会打扰)。

class Vector : public vector<int>
{
public:
    Vector operator+(const Vector& vec);
};
Vector Vector::operator+(const Vector& vec)
{
    for (int i = 0; i < vec.size(); i++)
    {
        this->push_back(vec[i]);
    }
    return *this;
}

让我先说这是一个黑客,不会给出如何使用vector来做到这一点的答案。相反,我们将依赖于sizeof(int) == sizeof(char32_t)并使用u32string来包含我们的数据。

这个答案非常清楚地表明,只有原语可以在basic_string中使用,任何大于32位的基元都需要编写自定义char_traits,但对于int我们可以只使用u32string

可以通过执行以下操作来验证此资格:

static_assert(sizeof(int) == sizeof(char32_t));

一旦建立了大小相等,并且知道不能使用非const dataemplaceemplace_back之类的东西,u32string就可以像vector<int>一样使用,并显着包含一个加法操作符:

const vector<int> first = {13};
const vector<int> second = {42};
const u32string concatenation = u32string(first.cbegin(), first.cend()) + u32string(second.cbegin(), second.cend());

[现场示例]

我遇到了这个问题,寻找同样的东西,并希望有比我想出的方法更简单的方法......好像没有。

因此,如果您不介意帮助程序模板类,一些迭代器技巧应该这样做:

#include <vector>
#include <iostream>
template<class T>
class concat
{
public:
    using value_type = typename std::vector<T>::const_iterator::value_type;
    using difference_type = typename std::vector<T>::const_iterator::difference_type;
    using reference = typename std::vector<T>::const_iterator::reference;
    using pointer = typename std::vector<T>::const_iterator::pointer;
    using iterator_category = std::forward_iterator_tag;
    concat(
        const std::vector<T>& first,
        const std::vector<T>& last,
        const typename std::vector<T>::const_iterator& iterator) : 
            mFirst{first},
            mLast{last},
            mIterator{iterator}{}
    bool operator!= ( const concat& i ) const
    {
        return mIterator != i.mIterator;
    }
    concat& operator++()
    {
        ++mIterator;
        if(mIterator==mFirst.end())
        {
            mIterator = mLast.begin();
        }
        return *this;
    }
    reference operator*() const
    {
        return *mIterator;
    }
private:
    const std::vector<T>& mFirst;
    const std::vector<T>& mLast;
    typename std::vector<T>::const_iterator mIterator;
};
int main()
{
    const std::vector<int> first{0,1,2,3,4};
    const std::vector<int> last{5,6,7,8,9};
    const std::vector<int> concatenated(
        concat<int>(first,last,first.begin()),
        concat<int>(first,last,last.end()));
    for(auto i: concatenated)
    {
        std::cout << i << std::endl;
    }
    return 0;
}

你可能必须实现operator++(int)或operator==,这取决于你的STL如何实现InputIterator构造函数,这是我可以为MingW GCC想出的最小迭代器代码示例。

玩得开心!:)