我在清理一些旧代码时遇到了问题。这是功能:
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_connectivity_data的问题。 get_connectivity_data通过引用获取std :: vector并用一些数据填充它。输出包含每个“块”的std :: vector。
基本上我的结论是,按原样保留我的代码要简单明了,更简洁,更短。
编辑:
所以我想象的最接近我的问题的答案就是:
std::for_each( chunks.begin(), chunks.end(),
bind( &chunk_vec_t::value::type::get_connectivity_data,
_1,
output[ std::distance( _1, chunks.begn() ]
)
);
然而,该代码无法编译,我对代码进行了一些修改以使其编译,但我遇到了两个问题:
关于zip_迭代器的答案看起来很好,直到我阅读更多内容并发现对于这种特殊用途,所需的额外代码量很大(绑定这个和那个等)。
EDIT2:
我找到了一个可接受的解决方案,这个解决方案在无关语法和清晰方面都很低,我已经在这里和下面发布了。
std::transform(chunks.begin(), chunks.end(), back_inserter(tmp), boost::bind(&ADTChunk::get_connectivity_data, _1) );
答案 0 :(得分:3)
经过一番工作,我想出了这个解决方案:
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。
答案 1 :(得分:2)
我认为你认为最好的办法是保持代码原样是正确的。如果你很难理解它(a)你正在写它并且(b)你理解你想要解决的确切问题,想象当有人在3年时间出现时会有多困难。必须了解你所写的问题和解决方案。
答案 2 :(得分:2)
如果没有看到整个班级的代码,很难确定什么会起作用。就个人而言,我认为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;
}
答案 3 :(得分:1)
关于lambda,我并没有真正了解你所驾驶的内容,但我可以为涉及STL容器的代码清理提出一些一般性建议。
使用所有STL容器类型的typedef:
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));
答案 4 :(得分:1)
您实际执行的操作是并行执行两个容器上的操作。这就是boost :: zip_iterator的设计目的。
但是,您需要并行处理容器的唯一原因是Chunk :: get_connectivity_data采用out参数。如果要按值返回(使用异常来报告错误),则可以使用插入迭代器。
答案 5 :(得分:1)
由于某种原因,STL初学者总是坚持使用vector :: iterator而不是更易读(和常量时间)的operator []。表达式it-chunks.begin()
应该告诉原作者他已经失去了smartass编码器游戏,毕竟需要一个不起眼的索引:
for (size_t i = 0, size = chunks.size(); i < size; ++i)
{
chunks[i]->get_connectivity_data(output[i]);
}
OP也可能会考虑丢失虚假返回码并使其成为const成员函数。