如何重构容器以直接使用谓词方法

how can I refactor a container to use a predicate method directly?

本文关键字:方法 谓词 何重构 重构      更新时间:2023-10-16

下面的代码段有效。然而,它有点难看,因为它使用静态方法来包装对谓词的方法调用。

换句话说,我想取代:

c.remove_if_true( Value::IsOdd );   // static method

c.remove_if_true( Value::isOdd );   // member method

应该减少一个间接级别,希望得到的代码会更清晰。

如何重构代码以直接调用isOdd(),而不必经过静态方法包装

但是,如果这个实现尽我所能清楚地编写这个代码,也请告诉我。TIA。

#include <vector>
#include <functional>
template< typename T >
class MyContainer
{
public:
    typedef std::function<bool(const T& t)>   PREDICATE;
public:
    void remove_if_true( PREDICATE predicate )
    {
        // NOTE: use implementation from KennyTM's answer below
    }
private:
    std::vector< T >  m_vec;
};
class Value
{
public:
    Value( int i ) : m_i( i ) { }
    bool isOdd() const { return m_i%2==1; }
    static bool IsOdd( const Value& v ) { return v.isOdd(); }
private:
    int m_i;
};

int main()
{
    MyContainer<Value> c;
    c.remove_if_true( Value::IsOdd );  // would like to replace with Value::isOdd here
}

使用KennyTM答案的解决方案

ataylor的建议std::mem_fun_ref()要求gcc 4.6.1和其他编译器不完全符合最新标准

#include <vector>
#include <algorithm>
#include <functional>
template< typename T >
class MyContainer
{
public:
    typedef std::const_mem_fun_ref_t<bool, T>  PREDICATE;
public:
    void remove_if( PREDICATE predicate )
    {
        auto old_end = m_vec.end();
        auto new_end = std::remove_if(m_vec.begin(), old_end, predicate);
        m_vec.erase(new_end, old_end);
    }
private:
    std::vector< T >  m_vec;
};
class Value
{
public:
    Value( int i ) : m_i( i ) { }
    bool isOdd() const { return m_i%2==1; }
private:
    int m_i;
};

int main()
{
    MyContainer<Value> c;
    c.remove_if( std::mem_fun_ref( &Value::isOdd ));
}
c.remove_if_true( std::mem_fn(&Value::isOdd) );

顺便说一句,你有什么理由需要避开std::remove_if吗?

void remove_if_true(PREDICATE predicate)
{
    auto old_end = m_vec.end();
    auto new_end = std::remove_if(m_vec.begin(), old_end, predicate);
    m_vec.erase(new_end, old_end);
}

c.remove_if_true( std::bind( &Value::isOdd, _1 ) );

您可以使用std::mem_fn_ref包装isOdd:

c.remove_if_true( std::mem_fun_ref(&Value::isOdd) );

使用lambdas的最佳方式:

c.remove_if_true( [] (const Value & v) { return v.get() % 2 == 0; } );

或更多自我评价:

auto isOdd = [] (const Value & v) { return v.get() % 2 == 0; };
c.remove_if_true( isOdd );