代码之家  ›  专栏  ›  技术社区  ›  jo

成员变量和STL算法

  •  4
  • jo  · 技术社区  · 15 年前
    #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::BIN来做它,但是我需要在没有Boost的情况下拥有C++ 03兼容的代码。

    3 回复  |  直到 15 年前
        1
  •  8
  •   xtofl Adam Rosenfield    15 年前

    要做到这一点,需要一个访问函数是绝对不干净的。但这就是当前的C++。

    你可以尝试使用 boost::bind ,这很容易实现技巧,或者使用 for( vector<int>::const_iterator it = v.begin(); .....) 循环。我发现,当创建函数变得太麻烦时,后者通常会导致代码更清晰。

    或者,避免Boost,创建自己的成员访问器填充程序函数。

    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 ) );
    
        2
  •  3
  •   Loki Astari    15 年前

    与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<T1,t2>
    及其访问器:std::select1st<t1>和std::select2nd<t2>

        3
  •  2
  •   Kirill V. Lyadvinsky    15 年前

    我最清楚的方法是 boost::bind :

    #include <boost/bind.hpp>
    
    ...
    
    transform(v.begin(), v.end(), back_inserter(is), bind( &Foo::i, _1 ) );
    

    当然,您可以创建自己的成员访问函数,但我相信它会降低代码的可读性。绑定是一个广为人知的库,因此使用它可以使代码非常可读,并且不需要读取助手函数(有时可能包含错误)。

    我更喜欢的第二种方法是只使用for循环(在本例中):

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

    也许使用这种简单的环并不流行,但它们是非常清楚的。