какую альтернативу std::not1 следует использовать при использовании std::tr1::bind или std::tr1::mem_fn

У меня есть вектор умного ptr моего класса Foo:

struct Foo
{
  Foo() : mEnabled( false ) {}

  bool mEnabled;

  bool isEnabled() const { return mEnabled; }
  void setEnabled( bool inEnabled ) { mEnabled = inEnabled; }
  /* ... */
};

typedef std::tr1::shared_ptr< Foo > tFooPtr;

typedef std::vector< tFooPtr > tFooVec;

У меня это работает хорошо:

 tFooVec foo_vector; // insert couple of elements
 size_t count = count_if( foo_vector.begin(), foo_vector.end(), std::tr1::mem_fn( &Foo::isEnabled ) );

Но какой функциональный «помощник» использовать, когда я хочу count_if «отключенные» объекты Foo

 size_t count = count_if( foo_vector.begin(), foo_vector.end(), std::not1( std::tr1::mem_fn( &Foo::isEnabled ) ) ); // does not compile

строка выше не компилируется:

/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_algo.h:446: error: no match for call to '(std::unary_negate<std::tr1::_Mem_fn<bool (Foo::*)()const> >) (std::tr1::shared_ptr<Foo>&)'
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_function.h:322: note: candidates are: bool std::unary_negate<_Predicate>::operator()(const typename _Predicate::argument_type&) const [with _Predicate = std::tr1::_Mem_fn<bool (Foo::*)()const>]
make: *** [src/shared_ptr_tests.o] Error 1

(Используя g++ 4.1.2 в Linux)

Я думаю, что проблема компиляции возникает из-за того, что std::not1 использует std::unary_negate, что требует, чтобы функция / Predicate предоставила Predicate::argument_type . Последнее дается, когда Predicate происходит от std::unary_function sigh

Сказав это, я предполагаю, что std::tr1::mem_fn не использует std::unary_function и не предоставляет argument_type.

Решение, которое я сейчас использую, заключается в том, что теперь я использую boost::bind вместо std::tr1::bind

#include <boost/bind.hpp>
using namespace boost;
...
size_t countboost = count_if( foo_vector.begin(), foo_vector.end(), !( bind( &Foo::isEnabled, _1 )) );

Чтобы избежать осложнений (и путаницы), я заменил использование std::tr1::bind на boost::bind во всем своем коде.


person Carsten Greiner    schedule 07.05.2012    source источник
comment
Если вы можете использовать более поздние компиляторы (С++ 11), вместо этого вы можете использовать лямбда-выражения.   -  person stefaanv    schedule 07.05.2012
comment
с удовольствием... не могу - система, на которой скомпилирован мой код, не принадлежит мне. И что еще хуже, мой код должен быть скомпилирован с помощью xlC и в AIX. Итак, я придерживаюсь старомодных функторов.   -  person Carsten Greiner    schedule 07.05.2012
comment
Абсурдный ответ: size_t count = v.size() - std::count_if( v.begin(), v.end(), std::tr1::mem_fn(&Foo::isEnabled));. Иногда самый простой ответ — избежать проблемы.   -  person David Rodríguez - dribeas    schedule 07.05.2012
comment
count_if - это просто пример... Я также хочу применить remove_copy_if. Может быть, мне следует использовать это и в моем примере.   -  person Carsten Greiner    schedule 07.05.2012


Ответы (2)


!boost::bind(... у меня работает:

  bool test(int i)
  {
    return i < 2;
  }

  TEST( boost_bind_test, negateTest )
  {
    std::vector<int> vec;
    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);

    ASSERT_EQ(2, count_if( vec.begin(), vec.end(), !boost::bind(&test, _1)));
  };
person Christopher Oezbek    schedule 07.05.2012
comment
size_t countN = count_if(foo_vector.begin(), foo_vector.end(), ! ( std::tr1::mem_fn( &Foo::isEnabled ) ) ); приводит к: ../src/shared_ptr_tests.cpp:217: ошибка: нет совпадения с оператором! в '!std::tr1::mem_fn [с _Tp = bool ()()const, _Class = Foo](&Foo::isEnabled)' ../src/shared_ptr_tests.cpp:217: примечание: кандидаты: оператор! (bool) ‹встроенный› - person Carsten Greiner; 07.05.2012
comment
@CarstenGreiner Какую версию boost вы используете? Эта функция была добавлена ​​в устаревшей версии Boost 1.33. - person pmr; 07.05.2012
comment
ну, ребята, мы говорим не о boost в начале, а о std::tr1 - я знаю, что tr1 реализован в boost, но я не использую непосредственно включение boost. Итак, да, у меня есть boost 1_44, но здесь я ограничиваюсь std:tr1. (может быть, я пойду и передумаю использовать boost). - person Carsten Greiner; 07.05.2012
comment
сейчас использую boost::bind, и мне нужно было добавить этот шаблон template<class T> inline T * get_pointer(std::tr1::shared_ptr<T> const & p) { return p.get(); } Последнее связано с тем, что я использую std::tr1::shared_ptrне boost::shared_ptr ) - person Carsten Greiner; 07.05.2012

Основная проблема заключается в том, что mem_fun(isEnabled) принимает const Foo *, тогда как алгоритм count_if передает shared_ptr<Foo> своему предикату.

Я не совсем уверен, почему это нормально работает с mem_fn( &Foo::isEnabled ), но не работает с not1(mem_fn( &Foo::isEnabled )). Все, что я могу думать, это то, что дополнительная оболочка вызывает необходимость в другом преобразовании. Но вы можете просто обойти это:

bool sharedEnabled(tFooPtr x) {
  return x->isEnabled();
}

size_t count2 = std::count_if( foo_vector.begin(), foo_vector.end(), std::not1( std::ptr_fun(&sharedEnabled ) ) );
person Steve Jessop    schedule 07.05.2012