【问题标题】:C++ Copy data from float vector to a vector of float pairsC++ 将数据从浮点向量复制到浮点对向量
【发布时间】:2014-06-29 09:48:21
【问题描述】:

我有一个目标标准向量:

 std::vector<std::pair<float,float> > allVertices;

为什么我要使用对,因为每 2 个浮点存在位置 pair(x,y)。现在,我有一个源 std:: 向量,它具有所有这些位置,但作为浮点数组(称为 m_vertices)。

我需要将所有数据从 m_vertices 复制到 allVertices 的末尾,并在复制过程中对数据进行转换。

std::transform 想到了Lambda,但我不知道如何从浮点向量复制到浮点对向量。

天真的:

    std::transform(m_vertices.begin(),m_vertices.end(),allVertices.end(),
                [](float x,float y)->std::pair<float,float>
            {
                return std::pair<float,float>(x * 100.0f,y * 100.0f)  ;
            }
            );

给我编译时错误:

错误 C2064:术语不计算为带 1 个参数的函数

还有一些更丑陋的东西。

顺便说一句,如果有人可以指出如何在 std::pair 结构中不需要的情况下转换数据对,那对我来说会更有帮助。

更新:

由于一些答案建议使用典型的迭代器,我想强调一下,我真的很想看看功能解决方案。如果可能的话。

【问题讨论】:

标签: c++ c++11 vector


【解决方案1】:

这里的编译器信息很清楚:您的 lambda 必须采用 一个 输入参数,但您的 lambda 采用两个输入参数 xy。您根本不能将std::transform 用于您的任务,因为std::transform 只接受单个值并转换它们,而不是值对。

以下是完成任务的三种可能方式:

简单的旧命令式编程

为什么不简单地使用这样的普通旧非功能方式:

for(auto it = m_vertices.begin(); it != m_vertices.end();++it){
    float x = *it;
    ++it;
    float y = *it;
    all_vertices.emplace_back(x*100f,y*100f);
}

确保m_vertices的大小是偶数;否则这段代码当然会崩溃。

Lamdas 和函数式编程很不错,但有时简单地以命令方式进行会更容易。

编写自己的对变换函数

您可以通过以下方式编写一个使用 lamdba 进行归约的函数:

template< class InputIt, class OutputIt, class BinaryReducerOp >
OutputIt transformPairs( InputIt first1, InputIt last1, OutputIt d_first,
                    BinaryReducerOp reducer_op );
    for(auto it = first1; it != last1;++it){
        auto& x = *it;
        ++it;
        if(it == last1) throw; // Input length not even!
        auto& y = *it;
        *d_first++ = reducer_op(x,y);
    }
}

现在您可以将此函数与您的 lambda 一起使用。即:

  transformPairs(m_vertices.begin(),m_vertices.end(),allVertices.end(),
                [](float x,float y)->std::pair<float,float>
            {
                return std::pair<float,float>(x * 100.0f,y * 100.0f)  ;
            }
            );

编写一对迭代器

正如 Steve Jessop 在他的评论中正确指出的那样,编写自己的对迭代器更加灵活,但也需要更多的工作。它可能看起来像这样(草图代码,这里没有编译器,可能包含小错误):

template<typename It> struct PairIterator {
private:
    mutable It it; // mutable so we can move around in operator*
public:
    typedef decltype(it*) Element;

    PairIterator(const It& it) : it(it) {}

    bool operator!=(const PairIterator<It>& other) const { return other != it; }

    std::pair<Element, Element> operator*() const {
        const Element& e1 = it*;
        ++it;
        const Element& e2 = it*;
        --it;
        return std::make_pair(e1,e2);
    }

    PairIterator<It>& operator++(){
        ++it;
        ++it;
        return *this;
    } 
}

template<typename It>
make_pair_it(const It& it){ return PairIterator<It>(it); }

现在你可以像这样使用std::transform

std::transform(make_pair_it(m_vertices.begin()),make_pair_it(m_vertices.end()),allVertices.end(),
                    [](std::pair<float,float> p)->std::pair<float,float>
                {
                    return std::pair<float,float>(p.first * 100.0f,p.second * 100.0f)  ;
                }
                );

【讨论】:

  • 那么什么是替代解决方案?我需要转换向量中的每 2 个数字。
  • 是的,当然这是潜在的替代方案之一,但我想尝试 C++11 的方式 :) 我的意思是,它不能真正在功能上完成吗?
  • @MichaelIV:我猜不是标准功能。这样做的原因是,将两个相邻的元素减少为一个并不经常使用,因此没有找到它进入 STL 的方式。如果您的代码中经常有这个用例并具有不同的转换,您可以使用我的代码构建一个函数,该函数采用对转换进行编码的 lambda。然后你可以使用 lambdas。我将添加一些示例代码,请稍等。
  • 哇,好技巧。您认为哪种解决方案会更快?
  • 注意:您可以发明一个迭代器适配器pair_iterator,而不是发明一个算法pair_iterator,它从其底层迭代器返回成对的连续元素。这样做的工作量更大,但如果您还想以这种方式使用transform 以外的算法,就会得到回报。
【解决方案2】:

对于您的问题,由于两个向量中的内存数组是相同的,您可以直接复制内存,这将是我认为最快的解决方案。

请注意,在将其应用于另一个案例之前,您必须确定自己在做什么,这很容易成为错误的根源。如果您尝试复制不同的类型(例如 double 到 float),它将不起作用。

allVertices.resize(m_vertices.size() / 2u);
std::copy_n(m_vertices.data(), m_vertices.size(), &(allVertices.front().first));

如果 m_vertices 大小不均匀,此代码也会中断。

然后您可以简单地使用一个范围广泛的基础 for 循环来应用您的处理

for (auto & pair: allVertices)
    treatment(pair);

【讨论】:

  • “你可以直接复制内存”你的意思是不会在目标向量中分配新的内存?但在这种情况下,数据的转换会影响初始向量,所以它可能不是一个选项因为源矢量数据必须保持不变。
  • 不,当然不是,内存是在“resize”函数中分配的,然后由copy_n(带有memmove)有效地复制。它避免像在其他一些解决方案中那样创建临时变量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
  • 1970-01-01
  • 2023-04-09
  • 2013-04-09
相关资源
最近更新 更多