【问题标题】:how to iterate into a smaller container (i.e. stride != 1)如何迭代到一个较小的容器(即步幅!= 1)
【发布时间】:2011-07-22 09:34:42
【问题描述】:

有一个问题很像here。不幸的是,这个问题没有引起太多的回应——我想我会问一个更具体的问题,希望可以提出一种替代方法。

我正在将二进制文件写入std::cin(使用tar --to-command=./myprog)。 二进制文件恰好是一组浮点数,我想将数据放入 std::vector<float> - 理想情况下是 c++ 方式。

我可以很好地生成std::vector<char>(感谢this answer

#include <fstream>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>

int
main  (int ac, char **av)
{
  std::istream& input = std::cin;
  std::vector<char> buffer;
  std::copy( 
        std::istreambuf_iterator<char>(input), 
           std::istreambuf_iterator<char>( ),
           std::back_inserter(buffer)); // copies all data into buffer
}

我现在想将我的std::vector&lt;char&gt; 转换为std::vector&lt;float&gt;,大概使用std::transform 和一个进行转换的函数(例如,char[2]float)。但是我很挣扎,因为我的std::vector&lt;float&gt; 的元素数量将是std::vector&lt;char&gt; 的一半。如果我可以以 2 的步幅进行迭代,那么我想我会很好,但从上一个问题来看,我似乎不能这样做(至少不能优雅地)。

【问题讨论】:

  • 为什么阅读char的?为什么不是std::string 的?目前还不清楚您希望能够输入什么,以及您想要完成什么。
  • @GMan,我想从输入到 cin 的二进制文件中完成 std​​::vector - 然后我可以使用库函数来解码 std::vector。如果通过 stings 进行操作更容易,那很好(我不清楚如何用 cin 做到这一点)。
  • @Tom:二进制文件的格式是什么?
  • @GMan 它是一个 gnuplot 二进制文件 - 它是一组很长的浮点数,但并非所有的浮点数都是数据,例如,第一个是浮点数(一个整数表示为浮点数)
  • @Tom:字节序是否值得关注?

标签: c++ stl iterator stl-algorithm


【解决方案1】:

在我看来,最好的答案是编写一对您自己的迭代器,以您想要的方式解析文件。您可以将 std::vector&lt;char&gt; 更改为 std::vector&lt;float&gt; 并使用相同的 streambuf 迭代器,前提是输入的格式在值之间至少有一个空格。

【讨论】:

    【解决方案2】:

    我会编写自己的类来读取两个字符并将其转换为浮点数。

    struct FloatConverter
    {
        // When the FloatConverter object is assigned to a float value
        // i.e. When put into the vector<float> this method will be called
        //      to convert the object into a float.
        operator float() { return 1.0; /* How you convert the 2 chars */ }
    
        friend std::istream& operator>>(std::istream& st, FloatConverter& fc)
        {
            // You were not exactly clear on what should be read in.
            // So I went pedantic and made sure we just read 2 characters.
            fc.data[0] = str.get();
            fc.data[1] = str.get();
            retun str;
        }
        char   data[2];
     };
    

    基于 GMan 的 cmets:

    struct FloatConverterFromBinary
    {
        // When the FloatConverterFromBinary object is assigned to a float value
        // i.e. When put into the vector<float> this method will be called
        //      to convert the object into a float.
        operator float() { return data }
    
        friend std::istream& operator>>(std::istream& st, FloatConverterFromBinary& fc)
        {
            // Use reinterpret_cast to emphasis how dangerous and unportable this is.
            str.read(reinterpret_cast<char*>(&fc.data), sizeof(float));
            retun str;
        }
    
        float  data;
    };
    

    然后像这样使用它:

    int main  (int ac, char **av)
    {
      std::istream& input = std::cin;
      std::vector<float> buffer;
    
      // Note: Because the FloatConverter does not drop whitespace while reading
      //       You can potentially use std::istream_iterator<>
      //
      std::copy( 
               std::istreambuf_iterator<FloatConverter>(input), 
               std::istreambuf_iterator<FloatConverter>( ),
               std::back_inserter(buffer));
    }
    

    【讨论】:

    • +1 表示方法。为了完成他的答案,根据他问题上的 cmets,它应该阅读 sizeof(float) char's 然后 reinterpret_cast 他们到 float,假设字节序不是问题。 (如果是,交换一些 char 的周围。)
    • 啊,酷,这看起来正是我要找的 - 让我试着解决它
    • 谢谢@Martin,而不是@Gman,我让您想象一下您刚刚替换的c和c++的可怕混搭:)
    【解决方案3】:

    使用升压范围适配器:

    boost::copy(istream_range(input)|stride(2),back_inserter(buffer));
    

    您可能需要编写自己的istreambuf_iterator,即trivial

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-03
      • 2019-10-21
      相关资源
      最近更新 更多