首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >通过移动从两个向量创建元组的向量

通过移动从两个向量创建元组的向量
EN

Stack Overflow用户
提问于 2019-07-11 03:20:58
回答 2查看 485关注 0票数 2

我想通过移动std::tuple的数据从两个std::vector创建一个std::vectorstd::vector<std::tuple<Ts...>>( std::vector of std::vector)。

让我们假设我有一个类似的结构(添加了std::cout来展示问题)。

代码语言:javascript
复制
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>>的右值引用定义一个operator+

代码语言:javascript
复制
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;
}

现在我正面临着这个问题。在运行此代码时

代码语言:javascript
复制
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";
}

输出是这样的:

代码语言:javascript
复制
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 constructor?在这里使用std::make_tuple是错误的方法吗?如何在不调用copy constructorcopy operator的情况下完成此操作

LIVE DEMO

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-07-11 03:30:43

您忘了在这里使用std::move

代码语言:javascript
复制
[](auto&& lhs_val, auto&& rhs_val) {
    return std::make_tuple(std::move(lhs_val), std::move(rhs_val));
});

记住,所有被命名的都是一个左值。

此外,您还必须修复迭代器:

代码语言:javascript
复制
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类型的std::move。事实上,我们可以不使用移动迭代器,只需使用左值引用调用lambda,然后我们就可以从中移动。

票数 5
EN

Stack Overflow用户

发布于 2019-07-11 03:38:28

您使用常量迭代器,并且不将元素std::move到元组中。这两种方法都会强制复制。更改为以下内容:

代码语言:javascript
复制
std::transform(std::make_move_iterator(lhs.begin()),
               std::make_move_iterator(lhs.end()),
               std::make_move_iterator(rhs.begin()),
               ret.begin(),
               [](auto&& lhs_val, auto&& rhs_val) {
    return std::make_tuple(std::move(lhs_val), std::move(rhs_val));
});
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56977339

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档