Как я могу рефакторинг контейнера для непосредственного использования метода предиката? - PullRequest
0 голосов
/ 06 марта 2012

Фрагмент ниже работает. Тем не менее, это немного уродливо, потому что он использует статический метод для переноса вызова метода в предикат.

Другими словами, я хотел бы заменить:

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

с чем-то вроде

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

Должен быть один уровень косвенности, и, надеюсь, результирующий код будет более понятным.

Как мне реорганизовать мой код для прямого вызова isOdd() без необходимости проходить через обертку статического метода?

Однако, если эта реализация настолько ясна, насколько я могу сделать этот код, также дайте мне знать. ТИА.

#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

предложение атайлора 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 ));
}

Ответы [ 4 ]

3 голосов
/ 06 марта 2012
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);
}
3 голосов
/ 06 марта 2012

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

2 голосов
/ 06 марта 2012

Вы можете использовать std::mem_fn_ref для упаковки isOdd:

c.remove_if_true( std::mem_fun_ref(&Value::isOdd) );
1 голос
/ 06 марта 2012

Лучший способ использовать лямбды:

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 );
...