Generalizing a function template



 DEVELOP > c-Plus-Plus > Generalizing a function template

LINK TO THIS PAGE  


rating :  0   |  0


  Page 1 of 1

1

 
Topic: DEVELOP > c-Plus-Plus
User: "Szabolcs"
Date: 19 Jan 2008 12:40:58 PM
Object: 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<double> apply(const array<double> &source) {
array<double> result(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
}
.

User: "Jerry Coffin"

Title: Re: Generalizing a function template 19 Jan 2008 03:20:20 PM
In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
@h11g2000prf.googlegroups.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<double> apply(const array<double> &source) {
array<double> result(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<A> apply(const array<B> &source, A (*fun)(B)) {
array<A> result(source.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.
.

User: "Jerry Coffin"

Title: Re: Generalizing a function template 19 Jan 2008 03:59:01 PM
In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
@h11g2000prf.googlegroups.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<double> apply(const array<double> &source) {
array<double> result(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<A> apply(const array<B> &source, A (*fun)(B)) {
array<A> result(source.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_type> &source, F f)
{
typedef typename array<typename F::argument_type>::size_type s_type;
array<typename F::result_type> results(source.size());
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_function, something like this:
struct func : public std::unary_function<int, double> {
double operator()(int input) { return sqrt(double(input)); }
};
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.
.

User: "Salt_Peter"

Title: Re: Generalizing a function template 19 Jan 2008 02:57:06 PM
On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail.com> 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<double> apply(const array<double> &source) {
array<double> result(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<T> apply(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_iterator< 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
*/
.
User: "SzH"

Title: Re: Generalizing a function template 19 Jan 2008 03:24:08 PM
On Jan 19, 9:57 pm, Salt_Peter <pj_h...@yahoo.com> wrote:

On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail.com> 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<double> apply(const array<double> &source) {
array<double> result(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<T> apply(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_iterator< 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
.


User: "Gianni Mariani"

Title: Re: Generalizing a function template 19 Jan 2008 03:07:36 PM
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<double> apply(const array<double> &source) {
array<double> result(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
}

Is this what you mean ?
template<typename T, typename S, T (*fun)(S)>
array<T> apply(const array<S> &source) {
array<T> result(source.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 );
}
.
User: "SzH"

Title: Re: Generalizing a function template 19 Jan 2008 03:20:10 PM
On Jan 19, 10:07 pm, Gianni Mariani <gi4nos...@mariani.ws> wrote:

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<double> apply(const array<double> &source) {
array<double> result(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
}


Is this what you mean ?

template<typename T, typename S, T (*fun)(S)>
array<T> apply(const array<S> &source) {
array<T> result(source.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 );

}

Thanks for the reply!
Yes, that's what I mean, except that I would like to avoid having to
explicitly specify the types "double" and "float". I would just like
to write apply<fx>(x);
Maybe this is problematic if fx is allowed to have a different return
type than its argument's type. But let us consider the simpler case
when they are the same:
template<typename T, T (*fun)(T)>
array<T> apply(const array<T> &source) {
array<T> result(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
}
Here the compiler should be able to deduce what type T actually is
from the argument passed to apply(). Is is possible to somehow
exchange the order of template parameters, like
template<T (*fun)(T), typename T>
array<T> apply(const array<T> &source) { ... }
, to make it possible to call apply() as apply<fx>(some_array) ?
--
Szabolcs
.
User: "Gianni Mariani"

Title: Re: Generalizing a function template 20 Jan 2008 06:55:52 AM
SzH wrote:
....

, to make it possible to call apply() as apply<fx>(some_array) ?

Yeah, that kind of syntax would be nice, I can't see how you would do it
with just template parameters. To do that you would need a way of
specifying a function template parameter without any "known" types e.g.
typename <THING fun>
..... apply( .... )
The only "thing" template parameter type is a "typename" (or class).
Not even partial template specialization of a class will work since it
is illegal to have template parameters not used in the partial template
specialization
e.g. ... illegal:
template <int>
class apply;
template <typename T, typename S, T (*fun)(S) > // illegal pts
class apply< fun >
{
public:
const array<S> & source;
apply( const array<S> & isource )
: source( isource )
{}
operator array<T> ()
{
array<T> result(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
}
};
.




  Page 1 of 1

1

 


Related Articles
 

NEWER

pg.1232     pg.940     pg.716     pg.544     pg.412     pg.311     pg.234     pg.175     pg.130     pg.96     pg.70     pg.50     pg.35     pg.24     pg.16     pg.10     pg.6     pg.3     pg.1

OLDER