提问人:Manumerous 提问时间:11/9/2022 最后编辑:Manumerous 更新时间:11/10/2022 访问量:326
创建 const std::vector 作为两个 const std::vector 的串联
Create const std::vector as the concatenation of two const std::vector
问:
我想创建一个包含另外两个相同类型的所有元素。由于向量是 我不能使用连接两个 std::vectors 中提到的方法将其与两者逐步连接起来。const std::vector
const std::vector
const
const std::vector
#include <iostream>
#include <vector>
int main()
{
const std::vector<int> int_a{0,1};
const std::vector<int> int_b{2,3};
const std::vector<int> all_ints;
for (int i: all_ints)
std::cout << i << ' ';
return 0;
}
对于上面的示例,我想以某种方式定义输出是 .all_ints
0 1 2 3
这怎么能做到呢?
答:
创建一个函数,该函数接受其他两个向量,创建第三个向量,插入前两个向量的值,按值返回结果。然后将其分配给您的常量向量:
const std::vector<int> int_a{0,1};
const std::vector<int> int_b{2,3};
const std::vector<int> all_ints = concat(int_a, int_b);
评论
我实际上不知道创建这样的常量向量的本质是什么。但是一个简单的技巧是创建一个临时的非常量向量,并用前两个向量填充它,然后创建最终的常量向量。例如:
const std::vector<int> int_a{0,1};
const std::vector<int> int_b{2,3};
std::vector<int> middle(int_a);
middle.insert(middle.begin(),int_b.begin(),int_b.end());
const std::vector<int> all_ints(middle);
正如评论中建议的那样,最后一行可以写成:
const std::vector<int> all_ints = std::move(middle);
评论
middle
正如 @Ayxan Haqverdili 的回答中已经提到的,您可以创建一个用于初始化向量的串联函数。
对于这样的功能,我建议以下实现:
template <template <typename, typename> typename C, typename ... Args>
C<Args...> concat(const C<Args...> & lhs, const C<Args...> & rhs)
{
C<Args...> res(lhs.cbegin(), lhs.cend());
res.insert(res.cend(), rhs.cbegin(), rhs.cend());
return res;
}
注意:此实现泛化到除 之外的所有标准库序列容器。std::array
然后可以像这样使用:
const std::vector<int> a {1, 2, 3};
const std::vector<int> b {4, 5};
const std::vector<int> ab = concat(a, b);
另一种更简单的版本可能是:
template <typename C>
C concat(const C & lhs, const C & rhs)
{
C res(lhs.size() + rhs.size());
typename C::iterator it = std::copy(lhs.cbegin(), lhs.cend(), res.begin());
std::copy(rhs.cbegin(), rhs.cend(), it);
return res;
}
评论
reserve()
std::vector
std::vector
res
lhs
rhs
reserve
insert
reserve()
如果您只是想遍历两个向量,则可以使用自定义视图连接器来实现。以下操作比创建(和销毁)另一个容器只是为了在两个范围内进行迭代要有效得多。
#include <iostream>
#include <array>
#include <ranges>
#include <vector>
#include <utility>
template<typename T1, typename T2>
auto concat_view(T1& lhs, T2& rhs)
{
static_assert(std::is_same_v<std::decay_t<T1>, std::decay_t<T2>>);
using T1_ = std::remove_reference_t<T1>;
using T2_ = std::remove_reference_t<T2>;
if constexpr (std::is_const_v<T1_> || std::is_const_v<T2_>)
{
using Iter = typename std::decay_t<T1>::const_iterator;
return std::array<std::ranges::subrange<Iter>, 2>{std::as_const(lhs), std::as_const(rhs)} | std::views::join;
}
else
{
using Iter = typename std::decay_t<T1>::iterator;
return std::array<std::ranges::subrange<Iter>, 2>{lhs, rhs} | std::views::join;
}
}
int main()
{
std::vector<int> v1{1,2,3}, v2{4,5,6};
for (int& val : concat_view(v1, v2))
++val;
for (const auto& val : concat_view(std::as_const(v1), v2))
std::cout << val << '\n';
return 0;
}
评论
这是另一个实现,也可以很容易地修改,甚至可以在将来修改的内容。它不需要最新的 c++ 版本。all_ints
#include <vector>
#include <algorithm>
int main()
{
const std::vector<int> int_a{ 0,1 };
const std::vector<int> int_b{ 2,3 };
const std::vector<int> all_ints(int_a.size()+ int_b.size());
std::vector<int>& all_intsr = const_cast<std::vector<int>&>(all_ints);
std::copy(int_b.begin(), int_b.end(), std::copy(int_a.begin(), int_a.end(), all_intsr.begin()));
}
这利用了能够合法地将 a 转换为 a 并具有以下限制来防止 UB 的优势。不得修改矢量对象。这不包括向量所拥有的内容,它不是 const。既不修改矢量对象,也不修改矢量对象。以后修改它的元素也是合法的,例如这样。const vector&
vector
begin()
end()
all_intsr[3]=42;
评论
const
const
const
const
int_a
int_b
total_ints