我在清理一些旧代码时遇到了一个问题。这就是功能:
uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output )
{
output.resize(chunks.size());
for(chunk_vec_t::iterator it = chunks.begin(); it < chunks.end(); ++it)
{
uint32_t success = (*it)->get_connectivity_data(output[it-chunks.begin()]);
}
return TRUE;
}
我感兴趣的是将for循环清理为lambda表达式,但很快就陷入了如何将正确的参数传递给get_connection_data的困境。get_connectivity_data通过引用获取一个std::向量,并用一些数据填充它。输出包含每个"chunk"的std::矢量。
基本上,我的结论是,保持代码原样会更容易、更干净、更短。
编辑:
因此,正如我所设想的,我的问题最接近的答案是:
std::for_each( chunks.begin(), chunks.end(),
bind( &chunk_vec_t::value::type::get_connectivity_data,
_1,
output[ std::distance( _1, chunks.begn() ]
)
);
然而,该代码并没有编译,我对代码进行了一些修改以使其编译,但我遇到了两个问题:
- _1是一个智能ptr,std::distance对它不起作用,我想我需要使用&chunks[0]作为开始
- 由于_1是一个智能指针,我不得不做:&chunk_vec_t::value_type::ValueType::get_connectivity_data导致VC9编译器崩溃
关于zip_迭代器的答案看起来不错,直到我深入阅读它,发现对于这种特定的用途,需要大量的额外代码(绑定这个和那个,等等)。
第2版:
我找到了一个可接受的解决方案,它既不涉及无关语法,又清晰明了,我已经在这里和下面发布了它。
std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
经过一番努力,我想出了这个解决方案:
std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
它要求我更改get_connectivity_data以返回std::vector,而不是通过引用获取,还要求我将块的元素更改为boost::shared_ptr,而不是Loki::SmartPtr。
我认为您认为最好的做法是保持代码原样,这是正确的。如果你很难理解(a)你在写它,(b)你理解你试图解决的确切问题,想象一下,当有人在3年后出现,必须理解你写的问题和解决方案时,会有多困难。
如果没有看到整个类的代码,就很难确定什么会起作用。就我个人而言,我认为BOOST_FOREACH在这种情况下更干净,但出于参考目的,我可能会尝试使用lambdas(注意,我不能测试编译)来做这样的事情
uint32_t ADT::get_connectivity_data( std::vector< std::vector<uint8_t> > &output )
{
using namespace boost::lambda;
output.resize( chunks.size() );
std::for_each( chunks.begin(), chunks.end(),
bind( &chunk_vec_t::value::type::get_connectivity_data,
_1,
output[ std::distance( _1, chunks.begn() ]
)
);
return TRUE;
}
关于lambda,我真的不知道你在做什么,但我可以为涉及STL容器的代码清理提出一些一般性建议。
使用所有STL容器类型的typedefs:
typedef std::vector<uint8_t> Chunks;
typedef std::vector<Chunks> Output;
uint32_t ADT::get_connectivity_data( Output &output )
既然你在谈论使用Boost,那就使用Boost。Foreach:
BOOST_FOREACH(chunk_vec_t::value_type &chunk, chunks)
uint32_t success =
chunk->get_connectivity_data(output[std::distance(&chunk, chunks.begin())]);
在黑暗中刺破"lambda"的东西:
typedef const boost::function2<uint32_t, chunk_vec_t::value_type, Chunks>
GetConnectivity;
uint32_t ADT::get_connectivity_data(Output &output, GetConnectivity &getConnectivity)
{
output.resize(chunks.size());
BOOST_FOREACH(chunk_vec_t::value_type &chunk, chunks)
uint32_t success =
getConnectivity(chunk, output[std::distance(&chunk, chunks.begin())]);
return TRUE;
}
然后你可以这样称呼它:
get_connectivity_data(output,
boost::bind(&chunk_vec_t::value_type::get_connectivity_data, _1, _2));
您实际要做的是对两个容器并行执行操作。这就是boost::zip_iterator的设计目的。
但是,您需要并行处理容器的唯一原因是Chunk::get_connectivity_data获取了一个out参数。如果它是按值返回(使用异常报告错误),您可以只使用插入迭代器。
由于某些原因,STL初学者总是坚持使用向量::迭代器,而不是更可读的(和恒定时间)运算符[]。表达式it-chunks.begin()
应该告诉原作者,他已经输掉了smartass编码器游戏,毕竟需要一个不起眼的索引:
for (size_t i = 0, size = chunks.size(); i < size; ++i)
{
chunks[i]->get_connectivity_data(output[i]);
}
OP还可能考虑丢失伪返回代码,并将其作为常量成员函数。