Connecting Tech Pros Worldwide Forums | Help | Site Map

Generalizing a function template

Szabolcs
Guest
 
Posts: n/a
#1: Jan 19 '08

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

Salt_Peter
Guest
 
Posts: n/a
#2: Jan 19 '08

re: Generalizing a function template


On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail.comwrote:
Quote:
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<doubleapply(const array<double&source) {
array<doubleresult(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<Tapply(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
*/

Gianni Mariani
Guest
 
Posts: n/a
#3: Jan 19 '08

re: Generalizing a function template


Szabolcs wrote:
Quote:
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<doubleapply(const array<double&source) {
array<doubleresult(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<Tapply(const array<S&source) {
array<Tresult(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 );
}
SzH
Guest
 
Posts: n/a
#4: Jan 19 '08

re: Generalizing a function template


On Jan 19, 9:57 pm, Salt_Peter <pj_h...@yahoo.comwrote:
Quote:
On Jan 19, 1:40 pm, Szabolcs <szhor...@gmail.comwrote:
>
Quote:
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).
>
Quote:
template<double (*fun)(double)>
array<doubleapply(const array<double&source) {
array<doubleresult(source.size());
for (int i = 0; i < source.size(); i++)
result[i] = fun(source[i]);
return result;
>
Quote:
}
>
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<Tapply(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
Jerry Coffin
Guest
 
Posts: n/a
#5: Jan 19 '08

re: Generalizing a function template


In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
@h11g2000prf.googlegroups.com>, szhorvat@gmail.com says...
Quote:
>
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<doubleapply(const array<double&source) {
array<doubleresult(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(const array<B&source, A (*fun)(B)) {
array<Aresult(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.
Jerry Coffin
Guest
 
Posts: n/a
#6: Jan 19 '08

re: Generalizing a function template


In article <b63330f7-e3e1-4fcc-b25d-ee035894e833
@h11g2000prf.googlegroups.com>, szhorvat@gmail.com says...
Quote:
>
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<doubleapply(const array<double&source) {
array<doubleresult(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(const array<B&source, A (*fun)(B)) {
array<Aresult(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_typeresults(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.
Closed Thread