我经常看到你可以用stl算法替换所有手写/原始循环。只是为了提高我的C ++知识,我一直在努力。
用数据填充std :: vector我使用for循环和循环索引。
unsigned int buffer_size = (format.getBytesPerSecond() * playlen) / 1000;
// pcm data stored in a 'short type' vector
vector<short> pcm_data;
for (unsigned int i = 0; i < buffer_size; ++i)
{
pcm_data.push_back( static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)) );
}
上面的代码工作正常,你可以看到我使用for循环索引&#39; i&#39;为了使算法正确。
有人如何用标准中的内容替换for循环?
我见过的几乎只允许我这样做的函数是std :: transform和std :: generate,但是这两个函数都不起作用,因为我需要一个索引值来增加代码。
EG:
generate_n(begin(pcm_data), buffer_size, [] ()
{
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)); //what is i??
});
transform(begin(pcm_data), end(pcm_data), begin(pcm_data) [] (???)
{
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)); //what is i??
});
或者我只是过分了解&#34;没有原始循环&#34;
答案 0 :(得分:7)
这里真正的解决方案是定义一个合适的解决方案 迭代器,类似于:
class PcmIter : public std::iterator<std::forward_iterator_tag, short>
{
int myIndex;
double myAmplitude;
double myFrequency;
short myValue;
void calculate()
{
myValue = myAmplitude * std::sin( 2 * M_PI * myIndex * frequency );
}
public:
PcmIter( int index, amplitude = 0.0, frequency = 0.0 )
: myIndex( index )
, myAmplitude( amplitude )
, myFrequency( frequency )
{
calculate();
}
bool operator==( PcmIter const& other ) const
{
return myIndex == other.myIndex;
}
bool operator!=( PcmIter const& other ) const
{
return myIndex != other.myIndex;
}
const short& operator*() const
{
return myValue;
}
PcmIter& operator++()
{
++ myIndex;
calculate();
}
PcmIter operator++( int )
{
PcmIter results( *this );
operator++();
return results;
}
};
在实践中,我怀疑你可以顺其自然
operator*
返回一个您在此时计算的值,
并且没有myValue
成员。
使用:
std::vector<short> pcmData(
PcmIter( 0, amplitude, frequency),
PcmIter( buffer_size ) );
(幅度和频率与结束无关 迭代器,因为它永远不会被解除引用。)
理想情况下,这将是一个random_access_iterator,以便 向量的构造函数将计算元素的数量,和 预先分配它们。这涉及实施更多 但是,功能。
如果你勇敢,并且必须做很多类似的事情,那么你 可以考虑将迭代器作为模板 实例化你感兴趣的功能。
虽然我最近没有机会和他们一起玩,但是
你正在使用Boost,你可能会考虑链接
一个transform_iterator
和一个counting_iterator
。它仍然是
有点罗嗦,但在Boost做过迭代器的人做了
鉴于STL的设计有些破碎,他们能做到最好
迭代器。
答案 1 :(得分:5)
您可以简单地使用“generate_n”范围内的变量来声明您的变量。
unsigned int i = 0;
generate_n(begin(pcm_data), buffer_size, [&] ()
{
return static_cast<short>(amplitude * sin((2 * M_PI * (i++) * frequency) / format.SampleRate)); //what is i??
});
答案 2 :(得分:5)
我会推荐counting_iterator
in Boost Library。一对计数迭代器为您提供一个整数范围。显然,没有底层容器。它提供整数&#34;懒惰&#34;。该库提供了工厂函数make_counting_iterator
来创建它。
back_insert_iterator
)中的 back_inserter
(带有工厂函数iterator
)有效地调用容器的成员push_back
。
使用这些成分,您可以将transform
与&#34;索引&#34;一起使用。
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
#include <boost/iterator/counting_iterator.hpp>
int main(int argc, char* argv[])
{
// Create a pair of counting iterators
auto first = boost::make_counting_iterator(0);
auto last = boost::make_counting_iterator(10);
vector<int> vi;
// Construct a vector of a few even number, as an example.
transform(first, last, back_inserter(vi), [](int i){ return 2 * i; });
// Print the result for check
copy(vi.begin(), vi.end(), ostream_iterator<int>{cout, " "});
return 0;
}
打印输出:
0 2 4 6 8 10 12 14 16 18
答案 3 :(得分:1)
不一定更好,但是使用stl:
的解决方案struct generate_value {
short operator() () const {return amplitude * sin((2 * M_PI * i++ * frequency) / format.SampleRate);}
private:
unsigned i = 0;
};
generate_n(back_inserter(pcm_data), buffer_size, generate_value{});
答案 4 :(得分:0)
我看到了一些我尚未见过的可能性。人们可以从一系列数字的迭代器开始:
template <class T>
class xrange_t {
T start;
T stop;
public:
xrange_t(T start, T stop) : start(start), stop(stop) {}
class iterator : public std::iterator<std::forward_iterator_tag, T> {
T current;
public:
iterator(T t) : current(t) {}
T operator *() { return current; }
iterator &operator++() { ++current; return *this; }
bool operator!=(iterator const &other) const { return current != other.current; }
bool operator==(iterator const &other) const { return current == other.current; }
};
iterator begin() { return iterator(start); }
iterator end() { return iterator(stop); }
};
template <class T>
xrange_t<T> xrange(T start, T stop) {
return xrange_t<T>(start, stop);
}
然后你将它用于一个ranged-for循环来完成真正的工作:
#include "xrange"
for (auto i : xrange(0, buffer_size))
pcm_data.push_back( static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)) );
另一种可能性是通过几个步骤完成工作:
std::vector<short> pcm_data(buffer_size);
std::iota(pcm_data.begin(), pcm_data.end(), 0);
std::transform(pcm_data.begin(), pcm_data.end(), pcm_data.begin(),
[](short i) {
return static_cast<short>(amplitude * sin((2 * M_PI * i * frequency) / format.SampleRate)));
}
);
首先用连续的i
值(即函数的输入)填充数组,然后将每个输入转换为匹配的输出值。
这有两个潜在的缺点:
i
的值可能超过short
中可以存储的值,则可能会在初始存储阶段截断输入值。不清楚您对int
使用i
是否反映了它可能具有更大幅度的可能性,或者默认情况下仅使用int
。