避免在具有不同迭代器的double for循环中几乎完全相同的代码重复

时间:2017-03-15 14:38:01

标签: c++

我必须使用两种不同的自定义类型构建图表我无法更改 因为他们的签名和目的几乎相同,所以我想删除一些代码重复 问题是它们返回一个不同的迭代器。

for (auto itFrom = m_pModelSpace->newIterator(); !itFrom->done() && nodesPassed < maxNodes; itFrom->step(), ++nodesPassed)
{
    /*
    ...
    */
    for (auto itTo = m_pModelSpace->newIterator(); itTo->objectId() != itFrom->objectId(); itTo->step())
    {
        /*
        ...
        */
    }
}

for (auto itFrom = m_pSelectionSet->newIterator(); !itFrom->done() && nodesPassed < maxNodes; itFrom->next(), ++nodesPassed)
{
    /*
    ...
    */
    for (auto itTo = m_pSelectionSet->newIterator(); itTo->objectId() != itFrom->objectId(); itTo->next())
    {
        /*
        ...
        */
    }
}

评论的代码完全相同 有什么方法可以解决这个问题吗? 我正在考虑一个包含2个构造函数的包装器,但是我还需要一个包装器用于对象迭代器。
另一个想法是两种类型的多重继承,但也感觉不对。

有什么建议吗?

Summurarized解决方案
感谢Mark B,我得出了以下解决方案:

namespace {
OdDbObjectIteratorPtr get_iterator(OdSmartPtr<OdDbBlockTableRecord>& pEntityCollection)
{
    return pEntityCollection->newIterator();
}

OdDbSelectionSetIteratorPtr get_iterator(OdSmartPtr<OdSelectionSet>& pEntityCollection)
{
    return pEntityCollection->newIterator();
}

void increment_iterator(OdDbObjectIteratorPtr& iter)
{
    iter->step();
}
void increment_iterator(OdDbSelectionSetIteratorPtr& iter)
{
    iter->next();
}

}

namespace spax{
template <typename Collection>
void ConnectionGraph::ConstructGraph(Collection& pEntityCollection, int maxNodes)
{
    // ...
    for (auto itFrom = get_iterator(pEntityCollection); !itFrom->done() && nodesPassed < maxNodes; increment_iterator(itFrom), ++nodesPassed)
    {
        //...
        for (auto itTo = get_iterator(pEntityCollection); itTo->objectId() != itFrom->objectId(); increment_iterator(itTo))
        {
            //...
        }
    }
}
}

因为Selection集返回了OdDbSelectionSetIteratorPtr的父OdSelectionSetIteratorPtr,所以我添加了另一个受此解决方案启发的函数来获取迭代器。 感谢您的帮助,我对结果非常满意。

4 个答案:

答案 0 :(得分:4)

使用具有间接级别的模板函数来处理迭代器增量怎么样?

void increment_iterator(<model space iterator type>& iter) { iter->step(); }
void increment_iterator(<selection set iterator type>& iter) { iter->next(); }

template <typename Container>
void execute_nested_loop(Container* c)
{
    for (auto itFrom = c->newIterator(); !itFrom->done() && nodesPassed < maxNodes; increment_iterator(itFrom), ++nodesPassed)
    {
        /*
        ...
        */
        for (auto itTo = c->newIterator(); itTo->objectId() != itFrom->objectId(); increment_iterator(itTo))
        {
            /*
            ...
            */
        }
    }
}

然后叫它:

execute_nested_loop(m_pModelSpace);
execute_nested_loop(m_pSelectionSet);

答案 1 :(得分:2)

您可以使用m_pModelSpace作为参数编写函数。如果您必须从本地上下文传递到该代码中使用的匹配项,请使用lambda:

auto advance = []( auto &it ) { it->step() };
auto loop = [&]( auto p ) {
     for (auto itFrom = p->newIterator(); !itFrom->done() && nodesPassed < maxNodes; advance( itFrom ), ++nodesPassed)
     {
        /*
         ...
        */
           for (auto itTo = p->newIterator(); itTo->objectId() != itFrom->objectId(); advance( itTo ) )
           {
               /*
                ...
               */
           }
     }
};
loop( m_pModelSpace );
advance = []( auto &it ) { it->next() };
loop( m_pSelectionSet );

注意:我将lamdas参数类型更改为auto,因为您说容器类型不相关。这适用于c ++ 14或更高版本,否则你可以使用模板。

答案 2 :(得分:1)

创建一个函数,将您使用的参数和放置相同代码的位置作为条目,并在每个循环中调用它

答案 3 :(得分:1)

在C ++中,规范化接口(摆脱step() vs next()),然后使用模板函数。