问题描述
我想创建一个 std :: tuple
的 std :: vector
的( std :: vector< std :: tuple< Ts ...>>
),通过移动 std :: vector
s的数据,从两个 std :: vector
移出.
I want to create a std::vector
of std::tuple
's (std::vector<std::tuple<Ts...>>
) from two std::vector
's by moving the data of the std::vector
s.
假设我有一个与此类似的结构(添加了 std :: cout
s以展示问题).
Let's assume I have a struct similar to this (added std::cout
s to showcase the problem).
template<typename T>
struct MyType
{
constexpr MyType() { std::cout << "default constructor\n"; }
constexpr MyType(const T& data) : m_data(data)
{
std::cout << "data constructor\n";
}
constexpr MyType(const MyType& other) : m_data(other.m_data)
{
std::cout << "copy constructor\n";
}
constexpr MyType(MyType&& other) noexcept : m_data(std::move(other.m_data))
{
std::cout << "move constructor\n";
}
~MyType() = default;
constexpr MyType& operator=(const MyType& other)
{
std::cout << "copy operator\n";
m_data = other.m_data;
return *this;
}
constexpr MyType& operator=(MyType&& other) noexcept
{
std::cout << "move operator\n";
m_data = std::move(other.m_data);
return *this;
}
private:
T m_data{};
};
现在,我们可以为 std :: vector< MyType< T>>
:
template<typename LhsT, typename RhsT>
constexpr auto operator+(std::vector<MyType<LhsT>>&& lhs, std::vector<MyType<RhsT>>&& rhs)
{
if(lhs.size() != rhs.size())
throw std::runtime_error("");
std::vector<std::tuple<MyType<LhsT>, MyType<RhsT>>> ret(lhs.size());
std::cout << "before transform\n";
std::transform(std::make_move_iterator(lhs.cbegin()),
std::make_move_iterator(lhs.cend()),
std::make_move_iterator(rhs.cbegin()),
ret.begin(),
[](auto&& lhs_val, auto&& rhs_val) {
return std::make_tuple(lhs_val, rhs_val);
});
std::cout << "after transform\n";
return ret;
}
现在我正在面对这个问题.运行此代码时
Now here I am facing the problem. When running this code
int main()
{
std::vector<MyType<int>> int_vec(1);
std::vector<MyType<float>> float_vec(1);
std::cout << "before move operator+\n";
auto int_float_tp_vec = std::move(int_vec) + std::move(float_vec);
std::cout << "after move operator+\n";
}
输出是这样的:
default constructor
default constructor
before move operator+
default constructor
default constructor
before transform
copy constructor
copy constructor
move operator
move operator
after transform
after move operator+
问题是:为什么要调用 copy构造函数
?在这里使用 std :: make_tuple
是错误的方法吗?如何在不调用 copy构造函数
或 copy运算符
的情况下执行此操作?
The question is: why is the copy constructor
called? Is using std::make_tuple
the wrong approach here? How can I do this without calling the copy constructor
nor the copy operator
?
推荐答案
您忘了在此处使用 std :: move
:
[](auto&& lhs_val, auto&& rhs_val) {
return std::make_tuple(std::move(lhs_val), std::move(rhs_val));
});
请记住,所有命名的都是左值.
Remember, everything named is an lvalue.
此外,您还必须修复迭代器:
In addition, you have to fix your iterators:
std::transform(lhs.begin(),
lhs.end(),
rhs.begin(),
ret.begin(),
[](auto&& lhs_val, auto&& rhs_val) {
return std::make_tuple(std::move(lhs_val), std::move(rhs_val));
});
您不能使用const迭代器制作move-iterator,这类似于应用于 const
类型的 std :: move
.实际上,我们可以不使用move-iterators,而只需使用左值引用调用lambda,然后我们就可以从中进行移动.
You cannot make a move-iterator out of const iterator, this is analogous to std::move
applied on a const
type. In fact, we can do without move-iterators and just get our lambda called with lvalue references, from which we can then move.
这篇关于通过移动从两个向量创建元组向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!