【问题标题】:Construction a vector from the concatenation of 2 vectors从 2 个向量的串联构造一个向量
【发布时间】:2016-02-18 15:40:11
【问题描述】:

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

例如:

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()); 

【问题讨论】:

  • @RyanP 我错过了回答我问题的内容吗?或者我应该假设我的问题的答案是否定的,因为那里没有任何东西可以回答它?
  • 如果您不能使用修改容器的方法并且您不想使用辅助方法并且向量没有加法运算符,那么恐怕您的问题的答案是否定的.
  • @JonathanMee 我同意它没有您正在寻找的具体答案,并且可能错过了。但是这个问题有 225 次投票,超过 10 万次浏览,而且我个人认为有很多答案,如果你想要的解决方案存在,它就不会被提及,因为这将是所有给出的答案。在这种情况下。
  • @JonathanMee 其中一些stackoverflow.com/a/4557156/4525052

标签: c++ vector constructor initialization addition


【解决方案1】:

不,如果您需要,这是不可能的

  • 没有定义辅助函数,并且
  • 生成的向量可以声明为const

【讨论】:

  • 看到我给出的所有答案,我有点难过,正是这个否定的答案让我获得了 C++ 金牌。 :o[
  • @Reader 我接受这个,但是这里有一个可以绕过这个问题的黑客:stackoverflow.com/a/35555016/2642059
【解决方案2】:
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;

【讨论】:

  • 不像其他答案那样非常理想。这将导致至少一个代价高昂的重新分配。
  • @NathanOliver:“这将导致至少一次重新分配” - 这取决于您的实施。如果 first 和 second 小于最小向量大小,则不会。
  • 最佳不是必需的;要求是允许将两个向量连接成一个常量向量。如果需要避免重新分配,则可以扩展运算符重载以使用保留大小 v1.size() + v2.size() 初始化可移动返回值。
  • @MartinBonner 我不得不说,从问题中复制代码并公然无视问题的要求,我有点惊讶。
【解决方案3】:

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

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

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

【讨论】:

  • 您可以通过 0 次重新分配 result 来做到这一点。
  • OP 询问如何在没有辅助函数的情况下执行此操作(我最初也没有看到。)
  • @LogicStuff:是的,你可以——但我建议这可能不值得额外的复杂性,除非你知道该函数将被大量使用。重新分配向量真的没有那么昂贵。
  • @MartinBonner 什么。?如果向量中有 1,000,000 个元素,那么当重新分配发生时,您有 1,000,000 个副本/移动要做。
  • @juanchopanza:是的。我的回答旨在被解读为“不。如果不编写辅助函数,就不能将向量初始化为两个向量的串联;这是编写辅助函数的方法。”
【解决方案4】:
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;
}

【讨论】:

  • 这不仅确实需要编写一个额外的函数,而且还需要我创建和使用一个非标准的类,并且它展示了一个更恶毒的版本重新分配问题比@MartinBonner 的答案:stackoverflow.com/questions/35485866/…
【解决方案5】:

让我先说这是一个 hack,并且不会回答如何使用 vector 执行此操作。相反,我们将依赖sizeof(int) == sizeof(char32_t) 并使用u32string 来包含我们的数据。

This answer 非常清楚只有 原语可以在 basic_string 中使用,并且任何大于 32 位的原语都需要编写自定义 char_traits,但对于int 我们可以使用u32string

可以通过以下方式验证此资格:

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

一旦确定大小相等,并且知道诸如非const dataemplaceemplace_back 之类的东西不能使用,u32string 可以像vector&lt;int&gt; 一样使用,显着地包含了一个加法运算符:

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

[Live Example]

【讨论】:

    【解决方案6】:

    我在寻找同样的东西时遇到了这个问题,并希望有一种比我想出的更简单的方法......似乎没有。

    因此,如果您不介意辅助模板类,则应该使用一些迭代器技巧:

    #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 提供的最小迭代器代码示例。

    玩得开心! :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      相关资源
      最近更新 更多