Переменные-члены и алгоритмы STL - PullRequest
4 голосов
/ 20 сентября 2009
#include <vector>
#include <functional>
#include <algorithm>
using namespace std;

struct Foo
{
    int i;
    double d;
    Foo(int i, double d) :
        i(i),
        d(d)
    {}
    int getI() const { return i; }
};

int main()
{
    vector<Foo> v;
    v.push_back(Foo(1, 2.0));
    v.push_back(Foo(5, 3.0));

    vector<int> is;

    transform(v.begin(), v.end(), back_inserter(is), mem_fun_ref(&Foo::getI));

    return 0;
}

Есть ли более чистый способ доступа к переменной-члену, а затем использовать функцию-член, как я описал выше? Я знаю, как это сделать, используя tr1 :: bind, но мне нужно иметь C ++ 03-совместимый код без надстройки.

Ответы [ 3 ]

8 голосов
/ 20 сентября 2009

Абсолютно нечисто, чтобы для этого нужна функция доступа. Но это текущий C ++.

Вы можете попробовать использовать boost::bind, что довольно легко, или просто итерировать вектор, используя цикл for( vector<int>::const_iterator it = v.begin(); .....). Я считаю, что последнее часто приводит к более ясному коду, когда создание функтора становится слишком хлопотным.

Или, избегая форсирования, создайте свою собственную функцию подкладки для доступа к элементам.

template< typename T, typename m > struct accessor_t {
   typedef m (T::*memberptr);

   memberptr acc_;

   accessor_t( memberptr acc ): acc_(acc){}
   // accessor_t( m (T::*acc) ): acc_(acc){}
   // m (T::*acc_);

   const m& operator()( const T& t ) const { return (t.*acc_); }
   m&       operator()( T& t       ) const { return (t.*acc_); }
};

template< typename T, typename m > accessor_t<T,m> accessor( m T::*acc ) {
   return accessor_t<T,m>(acc);
}

...

transform( v.begin(), v.end(), back_inserter(is), accessor( &C::i ) );
3 голосов
/ 20 сентября 2009

Как и std :: pair, вы можете писать объекты доступа или объекты.

#include <vector>
#include <algorithm>

struct Foo
{
    int i;
    double d;
};

struct GetI { int    operator()(Foo const& o) const { return o.i;}};
struct GetD { double operator()(Foo const& o) const { return o.d;}};

int main()
{
    std::vector<Foo>    v;
    std::vector<int>    t;
    std::transform(v.begin(), v.end(), std::back_inserter(t),GetI() );
}

Примечание: вы должны посмотреть на std :: pair
И его методы доступа: std :: select1st и std :: select2nd

2 голосов
/ 20 сентября 2009

Самый ясный способ для меня это boost::bind:

#include <boost/bind.hpp>

...

transform(v.begin(), v.end(), back_inserter(is), bind( &Foo::i, _1 ) );

Конечно, вы можете создать свою собственную функцию доступа к членам, но я верю, что это сделает ваш код менее читабельным. boost :: bind - широко известная библиотека, поэтому ее использование сделает ваш код довольно читабельным, и вам не нужно будет читать вспомогательные функции (которые могут иногда содержать ошибки)

Второй способ, который я предпочитаю, это просто использовать цикл for (в данном конкретном случае):

for ( vector<Foo>::const_iterator it = v.begin(), it != v.end(); ++it )
    is.push_back( it->i );

Может быть, такие простые петли не модно использовать, но они очень четкие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...