在C ++中删除重复模式

时间:2010-03-06 19:46:12

标签: c++ templates virtual

我至少有以下16种形式的功能。

bool Node::some_walker( Arg* arg1 )
{   
    if(this == NULL)
       return false;

    bool shouldReturn = false;

    if( this->some_walker_p(arg1, shouldReturn) ) //This line alone varies
        return true;

    if( shouldReturn ) // true is already returned
        return false;

    return this->std_walker(arg1);
}

函数some_walker_p是一个虚函数,我无法将其模板化。是否有任何解决方案可以避免此代码重复?

谢谢, 戈库尔。

3 个答案:

答案 0 :(得分:4)

这取决于私有函数的参数是否相似。以下解决方案是可能的,范围从简单到有限到复杂和通用:

  1. 等效=<使用member-function-pointer)
  2. 相同数字,不同类型=>对每个论点进行模板化)
  3. 不同数量/类型的参数=> se boost :: bind和function objects)
  4. 感谢您的评论。起初,我只发布了第一个解决方案,但是(如上所列)其他需要不同方法的情况。

    成员函数指针:

    bool Node::walker_caller(Arg* arg1, bool (Node::*memfn)(Arg*, bool))
    {   
        ...
        if( (this->*memfn)(arg1, shouldReturn) ) //This line alone varies
            return true;
        ...
    }
    
    bool Node::some_walker(Arg* arg1)
    {   
        return walker_caller(arg1, &Node::some_walker_p);
    }
    
    bool Node::other_walker(Arg* arg1)
    {   
        return walker_caller(arg1, &Node::other_walker_p);
    }
    

    旁注:我通常输入mem-fn-ptr来使语法更具可忍性。

    模板化参数:

    我假设你这里总有两个参数,但它们可以有不同的类型。

    如果你有一定数量的args-number(比如说1和2),你可以实现两次walker_caller,一个impl用于one-arg,一个用于two-arg,两个都是模板化的。

    template<class A1, class A2)
    bool Node::walker_caller(A1 arg1, A2 arg2, bool (Node::*memfn)(A1, A2, bool))
    {   
        ...
        if( (this->*memfn)(arg1, arg2, shouldReturn) ) //This line alone varies
            return true;
        ...
    }
    
    bool Node::some_walker(Arg* arg, OtherArg* other_arg)
    {   
        return walker_caller(arg, other_arg, &Node::some_walker_p);
    }
    
    bool Node::other_walker(OtherArg* other_arg, YetAnotherArg* yaa)
    {   
        return walker_caller(other_arg, yaa, &Node::other_walker_p);
    }
    

    功能对象:

    如果你的步行者使用广泛不同的数字和参数类型,你可能想使用boost :: bind,也许还有boost :: function。 (不需要使用后者,但会减少生成的代码大小......)

    // faster code, as the function object may be inlined, but
    // each call instantiates a different walker_caller, so exe might be bigger
    template<class F>
    bool Node::walker_caller(const F& fn)
    {   
        ...
        if( fn(shouldReturn) ) //This line alone varies
            return true;
        ...
    }
    
    // only one implementation, so smaller foot print but
    // all arguments need to be copied into a function objet
    // which may be a perf hit if the arguments are big
    // (this version is good to have when you inherit from Node...)
    bool Node::walker_caller(const boost::function<bool (bool)>& fn)
    {   
        ...
        if( fn(shouldReturn) ) //This line alone varies
            return true;
        ...
    }
    
    bool Node::some_walker(Arg* arg1)
    {   
        return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, _1));
    }
    
    bool Node::other_walker(Arg* arg1, OtherArg* arg2)
    {   
        return walker_caller(boost::bind(&Node::some_walker_p, this, arg1, arg2, _1));
    }
    

答案 1 :(得分:1)

您可以使用(非虚拟)模板函数调用虚拟(非模板)函数来模拟模板化虚拟函数。这可能有所帮助,具体取决于代码的结构。

答案 2 :(得分:1)

使用宏。

我知道得到一个糟糕的代表,但他们有合法的用途。一般来说,我认为在实现代码中使用它们比在接口代码中使用它们更容易接受,所以我会在这里考虑一下。

#define WALKER_MAYBE_DELEGATE( function_name, attempt, fallback, ArgType) \
void Node::function_name(ArgType arg) {\
...