在这种情况下如何避免代码重复问题?

时间:2015-10-23 06:56:06

标签: c++

我有两个类似的功能,即使用图形节点或边缘进行一些计算。

void foo(const VertexMgr& mgr, const std::string name)
{
    // Skipped..
    for (int i = 0; i< 100; ++i)
    {
        // Skipped
        const A& a = CreateSomething();
        for (IterType<Vertex> it = a->vertices(); it != NULL(); ++it)
        {
            // do something
        }
    }
}

void goo(const EdgeMgr& mgr, const std::string& name)
{
    // Skipped..
    for (int i = 0; i< 100; ++i)
    {
        // Skipped
        const A& a = CreateSomething();
        for (IterType<Edge> it = a->edges(); it != NULL(); ++it)
        {
            // do something
        }
    }
}

问题是:如何在这种情况下摆脱代码重复。 是否有可能的模板解决方案?

3 个答案:

答案 0 :(得分:6)

您可以使用Vertex / Edge和manager对象的模板参数,然后使用std::mem_fn来调用函数。

包装实际的函数调用以使调用更容易。也许像是

template<typename MgrT, typename ItrT, typename FunT>
void foo(const MgrT& mgr, const std::string& name, FunT& fn)
{
    for (int i = 0; i < 100; ++i)
    {
        // Skipped
        const A& a = CreateSomething();
        for (IterType<ItrT> it = fn(a); it != NULL(); ++it)
        {
            // do something
        }
    }
}

void foo(const EdgeMgr& mgr, const std::string& name)
{
    foo<EdgeMgr, Edge>(mgr, name, std::mem_fn(&A::edges));
}

void foo(const VerticeMgr& mgr, const std::string& name)
{
    foo<VertexMgr, Vertex>(mgr, name, std::mem_fn(&A::vertices));
}

未经测试,但希望能提供一个起点。

答案 1 :(得分:2)

除方法指针外,您可以

template <typename T> IterType<T> GetIterType(A&);

template <> IterType<Vertex> GetIterType<Vertex>(A& a) { return a->vertices(); }
template <> IterType<Edge> GetIterType<Edge>(A& a) { return a->edges(); }

template <typeame Mgr>
void foo(const Mgr& mgr, const std::string name)
{
    using itr_type = typename Mgr::itr_type; // That assumes that you add using in Mgr
    //else you have to create an external traits.

    // Skipped..
    for (int i = 0; i < 100; ++i)
    {
        // Skipped
        const A& a = CreateSomething();
        for (IterType<itr_type> it = GetIterType<itr_type>(a); it != NULL(); ++it)
        {
            // do something
        }
    }
}

另一种方法是使用auto it代替IterType<..> it,并使用通用名称重命名(或别名vertices() / edges()data())。

答案 2 :(得分:1)

这里有一个简单的方法来对这个功能进行构思:

template<class Manager>
void foo(const Manager& mgr, const std::string& name)
{
    // Skipped..
    for (int i = 0; i< 100; ++i)
    {
        // Skipped
        const A& a = CreateSomething();
        for (auto it = Manager::get_iterator(a); it != NULL(); ++it)
        {
            // do something
        }
    }
}

以及如何实现get_iterator

struct EdgeMgr {
    static IterType<Edge> get_iterator(A& a) {
        return a.edges();
    }
};
struct VertexMgr {
    static IterType<Vertex> get_iterator(A& a) {
        return a.vertices();
    }
};

要进一步使get_iterator对任何类型都有用,您可以使用模板:

struct EdgeMgr {
    template<class T>
    static IterType<Edge> get_iterator(T& a) {
        return a.edges();
    }
};
// ....
Manager::template get_iterator<A>(a)