Boost logo

Boost :

From: Shankar Sai (sai.shankar_at_[hidden])
Date: 2001-02-18 10:21:59


|> -----Original Message-----
|> From: Jens Maurer [mailto:Jens.Maurer_at_[hidden]]
|> Sent: Tuesday, February 13, 2001 1:24 AM
|> To: boost_at_[hidden]
|> Subject: Re: [boost] Adapters for member variables
|>
|>
|> Shankar Sai wrote:
|> > Is there any interest in a library that would enable
|> member variables
|> > to be used with the STL algorithms without having to write trivial
|> > functions? In case I'm not being clear <g>, here's an example.
|>
|> You have been advised of the lambda calculus libraries floating around.
|> However, I believe there may be a need for simple adapters
|> such as the one you propose for non-conforming compilers or minimizing
|> compile time.
|>
|> Please have a look at the function object and compose adapters already
|> present in boost for design guidance.
|>
|> http://www.boost.org/libs/functional/index.html
|> http://www.boost.org/libs/compose/index.htm
|>
|> It seems that the adapter compose_f_gx_hx probably does most of what
|> you want, so you may only need some functional wrapper around for
|> a data member.

Agreed.

|>
|> > template <class T, class Member, class Comp>
|> > struct member_comparer : public std::binary_function <T, T, bool>
|>
|> This interface does not seem flexible enough for the general case.
|> Don't you simply want some data_member<> template which just wraps
|> the member pointer?
|>

Agreed.

Thanks for the excellent comments. I didn't find time to do anything this
week, so the delayed posting. The idea is to enable writing code like the
following:

#include <string>
#include <iostream>

struct S
{
  int column1_;

  int column2_;

  std::string column3_;
};

std::ostream& operator << (std::ostream& os, S const& s)
{
  os << "\n" << s.column1_ << "\n";
  os << s.column2_ << "\n";
  os << s.column3_ << "\n\n";
  return os;
}

#include <vector>
#include <algorithm>
#include <iterator>
#include "compose.hpp" // From Boost

int main ()
{
  S x, y, z;

  x.column1_ = -1;
  y.column1_ = 0;
  z.column1_ = 1;

  x.column2_ = 0;
  y.column2_ = 0;
  z.column2_ = 0;

  x.column3_ = "0";
  y.column3_ = "1";
  z.column3_ = "2";

  std::vector <S> vec;

  vec.push_back (x);
  vec.push_back (y);
  vec.push_back (z);

  using boost::compose_f_gx_hx;

  int count_of_column1_less_than_column2 =

  std::count_if (vec.begin (), vec.end (),
                 compose_f_gx_hx (std::less <int> (),
                                      data_member (&S::column1_),
                                      data_member (&S::column2_)));

  // Sort on column3 in descending order
  
  using boost::compose_f_gx_hy;

  std::sort (vec.begin (), vec.end (),
             compose_f_gx_hy (std::greater <std::string> (),
                                  data_member (&S::column3_),
                                  data_member (&S::column3_)));
  std::copy (vec.begin (),
             vec.end (),
             std::ostream_iterator <S> (std::cout));
}

The actual code is below. This code has been tested on MSVC (SP3),
g++ 2.95.2 on Cygwin(Windows NT), Borland 5.5 (SP2).

#include <functional>

template <class T, class Member>
struct data_member_t : public std::unary_function <T, Member&>
{
  data_member_t (Member (T::*ptr)): ptr_(ptr)
  {
  }

  Member& operator () (T const& t)
  {
    return t.*ptr_;
  }

  const Member& operator () (T const& t) const
  {
    return t.*ptr_;
  }

  Member T::*ptr_;
};

template <class T, class Member>
data_member_t <T, Member>
data_member (Member (T::*ptr))
{
  return data_member_t <T, Member> (ptr);
}

Extensions i can think of are similar types/partial specializations
for handling pointers (dereferencing) and references (avoiding the
reference to a reference problem).

Contra: such members are not likely to be/should not be in "simple"
structs, which is what the adapter is aimed at. What do you think?
All comments/suggestions welcome.

Best Regards,
Sai Shankar


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk