template function as function parameter

R

rg

Hi all,

I was wondering if anyone had dealt with a similar problem. I need to use a
template function as the parameter for a particular function (also template
function).
The program compiles into an object file but then at the final stage it says
that it can't find template function. The platform is WindowsXP Pro, MSCV++
..Net.

More specifically what I want to do is write an atl algorithm that will also
accept another algorithm as a function parameter. This is inteface of the
outer algorithm:

template <class iterator, class outiterator, class Alg>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin, std::size_t slide, Alg alg)
{
std::size_t loop = std::distance( begin, end) / slide;
for ( std::size_t x = 0; x < loop; ++x, ++outbegin, begin =
std::advance( begin, size) ) // only do complete cycles, not parts
*outbegin = alg( begin, std::advance( begin, size) );
}

What I want to do with is perform some calculations on range on a sliding
basis. For example, if I have a array of 1000 values, I may want to
calculate the average of every 100 of those values.

Any help would be appreciated. Many Thanks in advance.

RG
 
D

David Hilsee

rg said:
Hi all,

I was wondering if anyone had dealt with a similar problem. I need to use a
template function as the parameter for a particular function (also template
function).
The program compiles into an object file but then at the final stage it says
that it can't find template function. The platform is WindowsXP Pro, MSCV++
.Net.

Are you falling into the trap where you place template code in the
implementation (.cpp) file instead of placing all of it in the header? See
the FAQ
(http://www.parashift.com/c++-faq-lite/containers-and-templates.html) for
info about linker errors with templates.
More specifically what I want to do is write an atl algorithm that will also
accept another algorithm as a function parameter. This is inteface of the
outer algorithm:

template <class iterator, class outiterator, class Alg>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin, std::size_t slide, Alg alg)
{
std::size_t loop = std::distance( begin, end) / slide;
for ( std::size_t x = 0; x < loop; ++x, ++outbegin, begin =
std::advance( begin, size) ) // only do complete cycles, not parts
*outbegin = alg( begin, std::advance( begin, size) );
}

This may have weird behavior on some inputs. Consider the behavior if the
distance is 1 and the slide is 2, where nothing is performed. Also, you
could accidentally run off the end of the container with the call to
advance(). Maybe something like this would be safer:

template <class iterator, class outiterator, class Alg>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin, std::size_t slide, Alg alg)
{
std::size_t dist = std::distance( begin, end );
for ( std::size_t x = 0; x < dist; x += slide, ++outbegin )
// only do complete cycles, not parts
iterator tmp = std::advance( begin, std::min(slide, dist-x) );
*outbegin = alg( begin, tmp );
begin = tmp;
}

The code above is untested.
 
D

David Hilsee

This may have weird behavior on some inputs. Consider the behavior if the
distance is 1 and the slide is 2, where nothing is performed. Also, you
could accidentally run off the end of the container with the call to
advance(). Maybe something like this would be safer:

Sorry, that comment about the end of the container, AFAICT, does not apply
to your code. It applies to the code that I provided if the call to
std::min is removed.
 
D

David Hilsee

template <class iterator, class outiterator, class Alg>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin, std::size_t slide, Alg alg)
{
std::size_t dist = std::distance( begin, end );
for ( std::size_t x = 0; x < dist; x += slide, ++outbegin )
// only do complete cycles, not parts
iterator tmp = std::advance( begin, std::min(slide, dist-x) );
*outbegin = alg( begin, tmp );
begin = tmp;
}

And for my final response to myself, I would like to point out that I didn't
even try to understand the comment that I cut-and-pasted from the original
code and made the code I posted almost completely irrelevant. *smacks
forehead*
 
J

John Harrison

Hi all,

I was wondering if anyone had dealt with a similar problem. I need to
use a
template function as the parameter for a particular function (also
template
function).
The program compiles into an object file but then at the final stage it
says
that it can't find template function. The platform is WindowsXP Pro,
MSCV++
.Net.

More specifically what I want to do is write an atl algorithm that will
also
accept another algorithm as a function parameter. This is inteface of the
outer algorithm:

template <class iterator, class outiterator, class Alg>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin, std::size_t slide, Alg alg)
{
std::size_t loop = std::distance( begin, end) / slide;
for ( std::size_t x = 0; x < loop; ++x, ++outbegin, begin =
std::advance( begin, size) ) // only do complete cycles, not parts
*outbegin = alg( begin, std::advance( begin, size) );
}

What I want to do with is perform some calculations on range on a sliding
basis. For example, if I have a array of 1000 values, I may want to
calculate the average of every 100 of those values.

Any help would be appreciated. Many Thanks in advance.

RG

I think I'd want to see the code that calls transform_slide.

Maybe I've having a bad day but I can't see how a template function (or
any sort of function) could be a suitable argument for class Arg, surely
you need a non-type template argument? Something like

template <class I, class OI, class T>
void transform_slide(I begin, I end, OI outbegin, size_t slide, T
(*Alg)(I, size_t))
{
}

john
 
J

John Harrison

Maybe I've having a bad day but I can't see how a template function (or
any sort of function) could be a suitable argument for class Arg, surely
you need a non-type template argument?

Yeah I've having a bad day, please ignore.

john
 
R

rg

Hi,
Thanks for your reply.
The algorithm that I am talking about is indeed in the header (.hpp) file. I
think the problem is that the template function is not actually instantiated
until it is used so when I send a pointer to it, there is nothing to point
at. I'm wondering if there's anything to deal with that. I tried:

using alg< vector<int>::iterator >;

but that didn't work.

Many thanks

RG
 
R

rg

Hi,

Thank you for your reply.

I was going to use it to calculate the rms power for each second in a sound
sample. Currently I'm using a rms_slide algorithm but I wanted to make a
more generic algorithm that can be used for sliding against any custom
algorithm.

Many Thanks

RG
 
D

David Hilsee

I think you might have overlooked John's request:

Also, it might be good to know exactly where the caller's code, and any code
it references, is located (defined in "blah.cpp"/declared in "blah.hpp").
 
R

rg

Hi,

Sorry for not having replied earlier, been extremely busy. Here is the code:

file stats.hpp
{
#insert...
.....

template <class iterator>
double rms(iterator begin, iterator end) // calculates the Root Mean
Square Power for some range of values
{
return std::sqrt(
std::accumulate(
begin, end, 0.0, boost::bind<double>(
std::plus<double>(), _1,
boost::bind(std::pow, _2, 2)
)
) / std::distance(begin, end)
);
}

template <class iterator, class outiterator>
void rms_slide ( iterator begin, iterator end, outiterator outbegin,
std::size_t slide) // calculates RMS over a sliding frame
{
std::size_t loop = std::distance( begin, end) / slide;
end = begin + slide;
for (
std::size_t x = 0;
x < loop;
++x, ++outbegin, std::advance( begin, slide), std::advance (
end, slide)
) // only do complete cycles, not parts
*outbegin = rms( begin, end );
}

} // end stats.hpp


file main.cpp
{
short * wav = new short[SIZE]; //array contain audio data
std::vector<int> power; // to hold rms power information over time

rms_slide( wav, wav + SIZE, std::back_inserter(power), SLIDE_SIZE );
// calculate RMS power for frames of size SLIDE_SIZE

delete[] wav;
}// end main.cpp


When I did this, I wondered whether I could develop a more generic version
of the slide algorithm which I described in my earlier post. Instead of
calling rms_slide, I would call:

transform_slide (
wav,
wav + SIZE,
std::back_inserter(power),
SLIDE_SIZE,
rms
);

and tell it to apply the rms algorithm over the sliding frame and insert the
value into the output iterator.

Hope it makes sense. Many Thanks for your help.

RG
 
D

David Hilsee

rg said:
Hi,

Sorry for not having replied earlier, been extremely busy. Here is the code:

file stats.hpp
{
#insert...
....

template <class iterator>
double rms(iterator begin, iterator end) // calculates the Root Mean
Square Power for some range of values
{
return std::sqrt(
std::accumulate(
begin, end, 0.0, boost::bind<double>(
std::plus<double>(), _1,
boost::bind(std::pow, _2, 2)
)
) / std::distance(begin, end)
);
}

template <class iterator, class outiterator>
void rms_slide ( iterator begin, iterator end, outiterator outbegin,
std::size_t slide) // calculates RMS over a sliding frame
{
std::size_t loop = std::distance( begin, end) / slide;
end = begin + slide;
for (
std::size_t x = 0;
x < loop;
++x, ++outbegin, std::advance( begin, slide), std::advance (
end, slide)
) // only do complete cycles, not parts
*outbegin = rms( begin, end );
}

} // end stats.hpp


file main.cpp
{
short * wav = new short[SIZE]; //array contain audio data
std::vector<int> power; // to hold rms power information over time

rms_slide( wav, wav + SIZE, std::back_inserter(power), SLIDE_SIZE );
// calculate RMS power for frames of size SLIDE_SIZE

delete[] wav;
}// end main.cpp


When I did this, I wondered whether I could develop a more generic version
of the slide algorithm which I described in my earlier post. Instead of
calling rms_slide, I would call:

transform_slide (
wav,
wav + SIZE,
std::back_inserter(power),
SLIDE_SIZE,
rms
);

and tell it to apply the rms algorithm over the sliding frame and insert the
value into the output iterator.

Hope it makes sense. Many Thanks for your help.

How about:

template <class iterator, class outiterator, class fun>
void transform_slide ( iterator begin, iterator end, outiterator
outbegin,
std::size_t slide, fun f )
{
std::cout << "A" << std::endl;
std::size_t loop = std::distance( begin, end ) / slide;
end = begin;
std::advance( end, slide );
for (
std::size_t x = 0;
x < loop;
++x, ++outbegin, begin = end, std::advance(end,slide)
)

*outbegin = f( begin, end );
}

template <class it>
double rms(it beg, it end) {return 0;}

// Allows the compiler to figure out what type the iterator
// should be
struct rms_wrapper {
template <class it>
double operator()(it beg, it end){
return rms(beg,end);
}
};

int main() {
std::vector<double> v;

transform_slide(v.begin(),v.end(),v.begin(),1,rms<std::vector<double>::itera
tor>);
transform_slide(v.begin(),v.end(),v.begin(),1,rms_wrapper());
}

But didn't you say something about a linker error? Can't find the function,
or something to that effect?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,566
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top