本文介绍了通过移动从两个向量创建元组向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个 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::vectors.

假设我有一个与此类似的结构(添加了 std :: cout s以展示问题).

Let's assume I have a struct similar to this (added std::couts 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.

这篇关于通过移动从两个向量创建元组向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-06 05:50