通常我不能使用std :: for_each,因为我对特定元素的逻辑取决于它的当前索引。为此,我发明了一个函数类,它包装了主函数并将其传递给当前索引。理想情况下,我想将它与lambda表达式一起使用。我创造的课程安全有效吗?还有更好的解决方案吗?我确实希望包装器的operator()返回lambda表达式的类型,但我无法弄明白。另外,我应该使用什么类型的索引?我应该通过值或引用将主仿函数存储在包装器中吗?
谢谢!
template<class FUNC>
class IndexFunctor
{
public:
typedef FUNC FUNC_T;
explicit IndexFunctor(const FUNC_T& func) : func(func), index(0) {}
// how can this return the return type of func?
template<class T>
void operator ()(T& param)
{
func(index++, param);
}
const FUNC_T& GetFunctor() const
{
return func;
}
int GetIndex() const
{
return index;
}
void SetIndex(int index)
{
this->index = index;
}
private:
FUNC_T func;
int index;
};
template<class FUNC>
IndexFunctor<FUNC> with_index(const FUNC& func)
{
return IndexFunctor<FUNC>(func);
}
void somefunc()
{
std::vector<int> v(10);
std::for_each(v.begin(), v.end(), with_index([](int index, int x){ std::cout << "[" << index << "]=" << x << std::endl; }));
}
答案 0 :(得分:4)
这应该是安全的,尽管为自己编写索引是相当简单的。
template <typename TInputIterator, typename TFunc>
TFunc counted_for_each(TInputIterator first, TInputIterator last, TFunc func)
{
for (size_t i = 0; first != last; ++first)
{
func(i++, *first);
}
return func;
}
减少代码并完成同样的事情。
答案 1 :(得分:4)
您从一开始就遇到问题是您想使用std::for_each
跟踪索引/计数器?然后一个解决方案就是简单地使用一个计数器变量,让一个lambda表达式捕获它。
std::vector<int> v{ 1, 2, 3 };
std::vector<int>::size_type i = 0;
std::for_each(begin(v), end(v), [i] (int x) mutable {
std::cout << "[" << i++ << "]=" << x << std::endl;
});
或者你可以这样做:
std::vector<int>::size_type i = 0;
for (auto itr = begin(v); itr != end(v); ++itr) {
std::cout << "[" << i++ << "]=" << *itr << std::endl;
}
在C ++ 11中使用基于范围的for循环可以简化为:
std::vector<int>::size_type i = 0;
for (auto itr : v) {
std::cout << "[" << i++ << "]=" << itr << std::endl;
}
注意:在上面的两个最后一个示例中,您必须记住每次运行for循环时都将索引计数器重置为0.
更新:如果你想迭代一个子范围保持跟踪索引,而不希望在循环之外有一个索引变量你可以使用std::distance
来计算索引,就像这样:
for (auto itr = begin(v); itr != end(v); ++itr) {
std::cout << "[" << std::distance(begin(v),itr) << "]=" << *itr << std::endl;
}
同样使用C ++ 14广义Lambda捕获表达式,您可以省略外部作用域中的计数器可变,只需使用初始化表达式创建i
作为lambda的成员:
std::for_each(begin(v), end(v), [i = 0] (int x) mutable {
std::cout << "[" << i++ << "]=" << x << std::endl;
});
答案 2 :(得分:3)
在我看来,std::for_each
基本上已过时使用基于范围的for( : )
循环,可能除了迭代子范围外。
即便如此,我只需使用基于范围的range_view
循环的template
for( : )
。 range_view
是一个简单的结构,其中begin()
和end()
方法返回迭代器:这样的对象可以传递给基于范围的for循环:
template<typename Iterator>
struct range_view {
Iterator b, e;
Iterator begin() const { return b; }
Iterator end() const { return e; }
};
template<typename Iterator>
range_view<Iterator> make_range_view( Iterator b, Iterator e ) {
return {b,e};
}
template<typename Container>
auto make_range_view( Container&& c )
-> decltype( make_range_view( std::begin(c), std::end(c) ) )
{ return ( make_range_view( std::begin(c), std::end(c) ) ); }
如果我需要索引,我会使用indexes
范围,或者如果非常热衷于在索引范围和原始容器(生成一系列元组)上执行范围 - zip
适配器。 indexes
是迭代器连续整数(boost
具有此类型),而zip
是获取两个范围或容器并返回范围超过tuple
的操作或pair
的数据。
现在我们可以改为修理你的。升级()
以使用完美转发和auto->decltype
返回值。但我不打扰:std
算法有它们的位置,但for_each
很少值得。
答案 3 :(得分:0)
我根据for_each:
制作了这个小算法namespace estd {
template<class InputIt, class BinaryFunction>
BinaryFunction for_each_with_index(
InputIt first, InputIt last, BinaryFunction f)
{
for (auto index = 0; first != last; ++first, ++index) {
f(*first, index);
}
return f;
}
}
然后我能够写一个这样的简单例子:
estd::for_each_with_index(
begin(strings_),
end(strings_),
[&sx, &sy](const auto& s, auto index) {
// Do something with my string and integer index
});
\ testd_for_each_with_index将适用于任何前向迭代器(任何提供*,++,!=的东西)。