Generalizing a function template

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Szabolcs

    Generalizing a function template


    I am looking for a way to generalize the function template below, so
    that it will work with any type, not just double. Is this at all
    possible in C++? I'd like to replace double (*fun)(double) with a
    generalized A (*fun)(B).


    template<double (*fun)(double)>
    array<doubleapp ly(const array<double&so urce) {
    array<doubleres ult(source.size ());
    for (int i = 0; i < source.size(); i++)
    result[i] = fun(source[i]);
    return result;
    }
  • Salt_Peter

    #2
    Re: Generalizing a function template

    On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail .comwrote:
    I am looking for a way to generalize the function template below, so
    that it will work with any type, not just double. Is this at all
    possible in C++? I'd like to replace double (*fun)(double) with a
    generalized A (*fun)(B).
    >
    template<double (*fun)(double)>
    array<doubleapp ly(const array<double&so urce) {
    array<doubleres ult(source.size ());
    for (int i = 0; i < source.size(); i++)
    result[i] = fun(source[i]);
    return result;
    >
    }

    I don't think a generalized A (*fun)(B) is a good idea, you'll be
    exposing yourself (ie: int (*fun)(double) ).

    To pass an array by reference you'ld have to deduce its Size:

    template< typename T, const std::size_t Size >
    void pass_by_ref(T(& array)[Size]) { ... }

    Which then begs the question: Why not use a std::vector instead?

    #include <iostream>
    #include <ostream>
    #include <vector>
    #include <algorithm>
    #include <iterator>

    template< typename T >
    std::vector<Tap ply(const std::vector<T>& vt, T(*fun)(const T t))
    {
    std::vector< T vresult(vt);
    std::transform( vt.begin(), vt.end(), vresult.begin() , fun);
    return vresult;
    }

    template< typename T >
    T square(const T t)
    {
    return t * t;
    }

    template< typename T >
    std::ostream& operator<<(std: :ostream& os, const std::vector< T >& vt)
    {
    std::copy( vt.begin(),
    vt.end(),
    std::ostream_it erator< T >(os, "\n") );
    return os;
    }

    int main()
    {
    std::vector< double v(5, 1.1);
    std::cout << v << std::endl;
    std::vector< double result = apply(v, square);
    std::cout << result << std::endl;
    }

    /*
    1.1
    1.1
    1.1
    1.1
    1.1

    1.21
    1.21
    1.21
    1.21
    1.21
    */

    Comment

    • Gianni Mariani

      #3
      Re: Generalizing a function template

      Szabolcs wrote:
      I am looking for a way to generalize the function template below, so
      that it will work with any type, not just double. Is this at all
      possible in C++? I'd like to replace double (*fun)(double) with a
      generalized A (*fun)(B).
      >
      >
      template<double (*fun)(double)>
      array<doubleapp ly(const array<double&so urce) {
      array<doubleres ult(source.size ());
      for (int i = 0; i < source.size(); i++)
      result[i] = fun(source[i]);
      return result;
      }
      Is this what you mean ?

      template<typena me T, typename S, T (*fun)(S)>
      array<Tapply(co nst array<S&source) {
      array<Tresult(s ource.size());
      for (int i = 0; i < source.size(); i++)
      result[i] = fun(source[i]);
      return result;
      }

      double fx( float );

      int main()
      {
      array< float x;
      apply< double, float, fx >( x );
      }

      Comment

      • SzH

        #4
        Re: Generalizing a function template

        On Jan 19, 9:57 pm, Salt_Peter <pj_h...@yahoo. comwrote:
        On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail .comwrote:
        >
        I am looking for a way to generalize the function template below, so
        that it will work with any type, not just double. Is this at all
        possible in C++? I'd like to replace double (*fun)(double) with a
        generalized A (*fun)(B).
        >
        template<double (*fun)(double)>
        array<doubleapp ly(const array<double&so urce) {
        array<doubleres ult(source.size ());
        for (int i = 0; i < source.size(); i++)
        result[i] = fun(source[i]);
        return result;
        >
        }
        >
        I don't think a generalized A (*fun)(B) is a good idea, you'll be
        exposing yourself (ie: int (*fun)(double) ).
        >
        To pass an array by reference you'ld have to deduce its Size:
        >
        template< typename T, const std::size_t Size >
        void pass_by_ref(T(& array)[Size]) { ... }
        >
        Which then begs the question: Why not use a std::vector instead?
        >
        #include <iostream>
        #include <ostream>
        #include <vector>
        #include <algorithm>
        #include <iterator>
        >
        template< typename T >
        std::vector<Tap ply(const std::vector<T>& vt, T(*fun)(const T t))
        {
        std::vector< T vresult(vt);
        std::transform( vt.begin(), vt.end(), vresult.begin() , fun);
        return vresult;
        >
        }
        >
        template< typename T >
        T square(const T t)
        {
        return t * t;
        >
        }
        >
        template< typename T >
        std::ostream& operator<<(std: :ostream& os, const std::vector< T >& vt)
        {
        std::copy( vt.begin(),
        vt.end(),
        std::ostream_it erator< T >(os, "\n") );
        return os;
        >
        }
        >
        int main()
        {
        std::vector< double v(5, 1.1);
        std::cout << v << std::endl;
        std::vector< double result = apply(v, square);
        std::cout << result << std::endl;
        >
        }
        >
        /*
        1.1
        1.1
        1.1
        1.1
        1.1
        >
        1.21
        1.21
        1.21
        1.21
        1.21
        */
        Thanks for the reply!

        Of course it is not difficult to get it working if (*fun) is an
        argument to the function (and not a template parameter), but I would
        like to keep it a template parameter so that it can be inlined when
        the function is small. gcc (with -O3) does not optimize away the
        function calls when (*fun) is an argument to the function.

        --
        Szabolcs

        Comment

        • Jerry Coffin

          #5
          Re: Generalizing a function template

          In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
          @h11g2000prf.go oglegroups.com> , szhorvat@gmail. com says...
          >
          I am looking for a way to generalize the function template below, so
          that it will work with any type, not just double. Is this at all
          possible in C++? I'd like to replace double (*fun)(double) with a
          generalized A (*fun)(B).
          >
          >
          template<double (*fun)(double)>
          array<doubleapp ly(const array<double&so urce) {
          array<doubleres ult(source.size ());
          for (int i = 0; i < source.size(); i++)
          result[i] = fun(source[i]);
          return result;
          }
          As long as you only want to support pointers to functions (not functors)
          it's pretty simple -- just templatize the input and output types:

          // warning: only minimally tested
          //
          // This depends on 'array; defining size_type, though size_t would also
          // work better than int without that requirement.
          //
          template <class A, class B>
          array<Aapply(co nst array<B&source, A (*fun)(B)) {
          array<Aresult(s ource.size());
          for (array<A>::size _type i=0; i<source.size() ; ++i)
          result[i] = fun(source[i]);
          return result;
          }

          You'll have to work a bit harder if you want to support functors. OTOH,
          std::transform already provides the same basic capability with slightly
          differetnt syntax and more flexibility, so I don't see much point in
          working much more on this...

          --
          Later,
          Jerry.

          The universe is a figment of its own imagination.

          Comment

          • Jerry Coffin

            #6
            Re: Generalizing a function template

            In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
            @h11g2000prf.go oglegroups.com> , szhorvat@gmail. com says...
            >
            I am looking for a way to generalize the function template below, so
            that it will work with any type, not just double. Is this at all
            possible in C++? I'd like to replace double (*fun)(double) with a
            generalized A (*fun)(B).
            >
            >
            template<double (*fun)(double)>
            array<doubleapp ly(const array<double&so urce) {
            array<doubleres ult(source.size ());
            for (int i = 0; i < source.size(); i++)
            result[i] = fun(source[i]);
            return result;
            }
            As long as you only want to support pointers to functions (not functors)
            it's pretty simple -- just templatize the input and output types:

            // warning: only minimally tested
            //
            // This depends on 'array; defining size_type, though size_t would also
            // work better than int without that requirement.
            //
            template <class A, class B>
            array<Aapply(co nst array<B&source, A (*fun)(B)) {
            array<Aresult(s ource.size());
            for (typename array<A>::size_ type i=0; i<source.size() ; ++i)
            result[i] = fun(source[i]);
            return result;
            }

            One way to make it work with function objects looks like this:

            template <class F>
            array<typename F::result_type>
            apply(const array<typename F::argument_typ e&source, F f)
            {
            typedef typename array<typename F::argument_typ e>::size_type s_type;

            array<typename F::result_typer esults(source.s ize());

            for (s_type i=0; i<source.size() ; ++i)
            results[i] = f(source[i]);
            return results;
            }

            Since this uses result_type and argument_type, you have to define those,
            which is usually done with std::unary_func tion, something like this:

            struct func : public std::unary_func tion<int, double{
            double operator()(int input) { return sqrt(double(inp ut)); }
            };

            FWIW, you can include both of these to overload apply to work with both
            functions and unary_function objects.

            --
            Later,
            Jerry.

            The universe is a figment of its own imagination.

            Comment

            Working...