Ответ 1
Попробуйте следующее:
points.erase(std::remove_if(points.begin(),
points.end(),
std::not1(std::mem_fun_ref(&Point2D::isValid))),
points.end());
У меня этот класс
class Point2D
{
public:
bool isValid();
// ...
private:
double x_, y_;
};
У меня есть std::vector< Point2D >
, и я хотел бы удалить недопустимые точки, теперь мне это нравится:
bool invalid ( const Point2D& p )
{
return !p.isValid();
}
void f()
{
std::vector< Point2D > points;
// fill points
points.erase( std::remove_if( points.begin(), points.end(), invalid ), points.end() );
// use valid points
}
Есть ли стандартный способ сделать это (красиво), например, без необходимости "дублирования" функциональности метода класса Point2D::isValid
?
Возможно, используя С++ 11 lambda (я не очень хорошо знаком с лямбдой)?
Попробуйте следующее:
points.erase(std::remove_if(points.begin(),
points.end(),
std::not1(std::mem_fun_ref(&Point2D::isValid))),
points.end());
Не совсем стандартный, но почти: вы можете использовать boost:: bind и выполнять следующие
points.erase( std::remove_if( points.begin(), points.end(),
!boost::bind(&Point2D::isValid, _1 )), points.end() );
Кстати, вы должны объявить метод isValid const.
Лямбда-версия также не будет чище, но у нее есть еще одно важное преимущество: местность. Вы видите код, в котором вы его используете:
points.erase( std::remove_if( points.begin(), points.end(),
[](const Point2D& p){
return !p.isValid();
}), points.end() );
Обратите внимание, что вам нужно изменить isValid
, чтобы сделать его функцией const
, иначе вы не можете называть его ссылкой-на-const (const Point2D&
).
Другой вариант - реализовать operator!
для вашего класса:
class Point2D{
// ... as before
public:
bool isValid() const;
bool operator!() const{
return !isValid();
}
};
Обратите внимание, что обе функции являются константами. Теперь вы можете реализовать общий отрицательный функтор:
struct negate{
template<class T>
bool operator()(T const& t){
return !t;
}
};
И используйте это:
points.erase( std::remove_if( points.begin(), points.end(), negate()), points.end() );
Вы можете сделать то, что хотите, используя комбинацию std::mem_fun_ref
и std::not1
:
points.erase( std::remove_if( points.begin(), points.end(),
std::not1( std::mem_fun_ref( &Point2D::isValid ) ) ),
points.end() );
Для чего это стоит, единственная "идиоматическая" часть об этом - стирать-удалить идиому.
Если Boost подходит для вас, используйте предложение @Randall Flagg вместе с boost::remove_erase_if
:
boost::remove_erase_if(points, !boost::bind(&Point2D::isValid, _1));
Я думаю, что вы ищете not1
Изменить: взглянув на ваш пример ближе, я не думаю, что вы можете сделать это любым другим способом, так как isValid()
является функцией-членом.