std::transform container => std::abs(container)

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Steven T. Hatton

    #1

    std::transform container => std::abs(container)

    This code works for dividing each element of a boost::array<> by a value of
    its element type:

    template <typename T, size_t S>
    inline boost::array<T, S>& operator/=( boost::array<T, S>& lhs, const T&
    rhs ) {
    std::transform( lhs.begin()
    , lhs.end()
    , lhs.begin()
    , std::bind2nd( std::divides<T> (), rhs ) );
    return lhs;
    }

    I want to use std::transform in a similar fashion to set each element of a
    boost::array<> to the result of applying std::abs() to it.

    The result can easily be obtained with this code:

    template <typename T, size_t Order_S>
    inline boost::array<T, Order_S>& abs( boost::array<T, Order_S>& v ) {
    for ( size_t i = 0; i < v.size(); i++ ) {
    v[ i ] = std::abs( v[ i ] );
    }
    return v;
    }

    I would like to know how to apply a function such as std::abs in a way
    similar to the use of std::bind2nd ( std::divides<T> (), rhs ) in the above
    example. How can this be done?

    --
    "If our hypothesis is about anything and not about some one or more
    particular things, then our deductions constitute mathematics. Thus
    mathematics may be defined as the subject in which we never know what we
    are talking about, nor whether what we are saying is true." - Bertrand
    Russell

  • Siemel Naran

    #2
    Re: std::transform container =&gt; std::abs(contai ner)

    "Steven T. Hatton" <susudata@setid ava.kushan.aa> wrote in message
    [color=blue]
    > std::transform( lhs.begin()
    > , lhs.end()
    > , lhs.begin()
    > , std::bind2nd( std::divides<T> (), rhs ) );[/color]
    [color=blue]
    > I want to use std::transform in a similar fashion to set each element of a
    > boost::array<> to the result of applying std::abs() to it.[/color]

    Here is one way

    int (*absolute)(int ) = &std::abs;
    std::transform( lhs.begin()
    , lhs.end()
    , lhs.begin()
    , absolute );



    Comment

    • Rob Williscroft

      #3
      Re: std::transform container =&gt; std::abs(contai ner)

      Steven T. Hatton wrote in news:AK2dnTrmn5 iu8C_cRVn-3w@speakeasy.ne t in
      comp.lang.c++:
      [color=blue]
      > This code works for dividing each element of a boost::array<> by a
      > value of its element type:
      >
      > template <typename T, size_t S>
      > inline boost::array<T, S>& operator/=( boost::array<T, S>& lhs,
      > const T&
      > rhs ) {
      > std::transform( lhs.begin()
      > , lhs.end()
      > , lhs.begin()
      > , std::bind2nd( std::divides<T> (), rhs ) );
      > return lhs;
      > }
      >
      > I want to use std::transform in a similar fashion to set each element
      > of a boost::array<> to the result of applying std::abs() to it.
      >
      > The result can easily be obtained with this code:
      >
      > template <typename T, size_t Order_S>
      > inline boost::array<T, Order_S>& abs( boost::array<T, Order_S>& v
      > ) {
      > for ( size_t i = 0; i < v.size(); i++ ) {
      > v[ i ] = std::abs( v[ i ] );
      > }
      > return v;
      > }
      >
      > I would like to know how to apply a function such as std::abs in a way
      > similar to the use of std::bind2nd ( std::divides<T> (), rhs ) in the
      > above example. How can this be done?
      >[/color]

      Write you're own functor:

      template < typename T > struct my_abs
      {
      typedef T return_type;

      T operator () ( T const &arg ) const
      {
      return std::abs( arg );

      /* or even better (ADL friendly version):
      */
      using std::abs;
      return abs( arg );
      }
      };

      The other alternative is to put a cast into the call to
      std::transform:

      std::transform(
      lhs.begin(), lhs.end(), lhs.begin(),
      static_cast< T (*)(T) >( std::abs )
      );


      The disadvantage here is that for T = short (for example) there
      is no overload short std::abs( short ), so the static_cast can't
      succeed. Also Argument Dependant Lookup (ADL) can't be used.

      Remember to include <cstdlib> and <cmath> so that you get all the
      overloads of std::abs, also unless you use an ADL friendly functor
      you'll need to include <complex> before calling std::abs if you want
      your code to work with std::complex (this also applies valarray).

      Rob.
      --

      Comment

      • Siemel Naran

        #4
        Re: std::transform container =&gt; std::abs(contai ner)

        "Rob Williscroft" <rtw@freenet.co .uk> wrote in message
        [color=blue]
        > template < typename T > struct my_abs
        > {
        > typedef T return_type;
        >
        > T operator () ( T const &arg ) const
        > {
        > return std::abs( arg );
        >
        > /* or even better (ADL friendly version):
        > */
        > using std::abs;
        > return abs( arg );
        > }
        > };[/color]

        The standard typedef names are result_type and argument_type. These allow
        compatibility with other standard binders in STL and boost like
        std::bind2nd.

        template < typename T > struct my_abs
        {
        typedef T argument_type;
        typedef T result_type;
        T operator () ( T const &arg ) const
        {
        using std::abs;
        return abs( arg );
        }
        };

        My preferred way is to derive from std::unary_func tion<argument_t ype,
        result_type>.

        template < typename T > struct my_abs : std::unary_func tion<T, T>
        {
        T operator () ( T const &arg ) const
        {
        using std::abs;
        return abs( arg );
        }
        };



        Comment

        • Rob Williscroft

          #5
          Re: std::transform container =&gt; std::abs(contai ner)

          Siemel Naran wrote in
          news:u9ysd.1033 433$Gx4.375699@ bgtnsc04-news.ops.worldn et.att.net in
          comp.lang.c++:
          [color=blue]
          >
          > The standard typedef names are result_type[/color]

          Thanks I always get this wrong.
          [color=blue]
          > and argument_type.[/color]

          AIUI (I haven't researched this myself, just going on snippets
          from usenet) argument_type isn't needed (used).
          [color=blue]
          > These
          > allow compatibility with other standard binders in STL and boost like
          > std::bind2nd.
          >
          > template < typename T > struct my_abs
          > {
          > typedef T argument_type;
          > typedef T result_type;
          > T operator () ( T const &arg ) const
          > {
          > using std::abs;
          > return abs( arg );
          > }
          > };
          >
          > My preferred way is to derive from std::unary_func tion<argument_t ype,
          > result_type>.[/color]

          Yep, but that does add an extra byte to the function object in some
          cases:

          struct my_functor : std::binary_fun ction< int, int, bool >
          {
          std::less< int > m_less;
          // operator here ...
          };

          The above has 2 subobjects of type std::binary_fun ction< int, int, bool >
          so EBO (Empty Base (class) Optimization) can't happen.

          I am perhapse being needlessly pedantic (and possibly I'm premeturly
          optimizing), OTOH typing "typedef T result_type;" is shorter (and IMO
          less cryptic) than writing " : std::unary_func tion< T, T > ".

          If only I could remember result_type not return_type all would be
          well :).

          Either way I have to lookup result_type or binary_function /
          unary_function as I'm actualy not sure the bool return type above
          shouldn't be the first argument.

          Rob.
          --

          Comment

          Working...