Template function adaptors

D

Drew McCormack

I have a self written Tensor class which I need to write a number of
elementwise operations for (eg sin, cos, abs, conj).

I am trying to implement most of these in terms of standard library
functions. Unfortunately, not all functions in the standard library are
constructed the same (eg some are template functions, some use
pass-by-value where others use pass by reference). To get around this,
I have tried to come up with an adaptor function. The main routine
looks like this:

template <typename T, typename S, S Func(T)>
Tensor<S> ElementwiseTensorOp( const Tensor<T> &subject ) {
Tensor<S> newTensor(subject.dimensions());
size_t n = subject.size();
S *newData = newTensor.data();
T *subjectData = subject.data();
for ( size_t i = 0; i < n; ++i ) newData = Func(subjectData);
}

I have written an adaptor function that converts pass by reference
functions to pass by value, like this:

template <typename T, typename S, S Func(const T&)>
S ArgTypeAdaptor(T arg) {
return Func(arg);
}

Now I try to use this in my Tensor functions, like so:

template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return
ElementwiseTensorOp<
complex<T>,
complex<T>,
ArgTypeAdaptor<complex<T>, complex<T>, std::conj<T> >
>( v );
}

This gives me the following error, which I don't understand:

error: no matching function for call to 'ElementwiseTensorOp(const
Periphery::Tensor<std::complex<double> >&)'

I am using gcc 4.0 on Mac OS X. Can anyone explain this to me? Is there
a better way to handle the argument type discrepancies than what I am
doing (eg STL adaptors)?

Drew McCormack
 
G

Gianni Mariani

Drew said:
I have a self written Tensor class which I need to write a number of
elementwise operations for (eg sin, cos, abs, conj).

I am trying to implement most of these in terms of standard library
functions. Unfortunately, not all functions in the standard library are
constructed the same (eg some are template functions, some use
pass-by-value where others use pass by reference). To get around this, I
have tried to come up with an adaptor function. The main routine looks
like this:

template <typename T, typename S, S Func(T)>
Tensor<S> ElementwiseTensorOp( const Tensor<T> &subject ) {
Tensor<S> newTensor(subject.dimensions());
size_t n = subject.size();
S *newData = newTensor.data();
T *subjectData = subject.data();
for ( size_t i = 0; i < n; ++i ) newData = Func(subjectData);
}

I have written an adaptor function that converts pass by reference
functions to pass by value, like this:

template <typename T, typename S, S Func(const T&)>
S ArgTypeAdaptor(T arg) {
return Func(arg);
}

Now I try to use this in my Tensor functions, like so:

template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return
ElementwiseTensorOp<
complex<T>,
complex<T>,
}

This gives me the following error, which I don't understand:

error: no matching function for call to 'ElementwiseTensorOp(const
Periphery::Tensor<std::complex<double> >&)'

I am using gcc 4.0 on Mac OS X. Can anyone explain this to me? Is there
a better way to handle the argument type discrepancies than what I am
doing (eg STL adaptors)?


The following code (derived from your code) compiles fine using gcc
4.0.0. Where is your problem ?

#include <complex>

using namespace std;

template <typename T>
struct Tensor
{
Tensor<T> dimensions() const;
size_t size() const;
T * data();
const T * data() const;
};

template <typename T, typename S, S Func(T)>
Tensor<S> ElementwiseTensorOp( const Tensor<T> &subject ) {
Tensor<S> newTensor(subject.dimensions());
size_t n = subject.size();
S *newData = newTensor.data();
const T *subjectData = subject.data(); // XXXXX - fixed this - XXXXX
for ( size_t i = 0; i < n; ++i ) newData = Func(subjectData);
}



template <typename T, typename S, S Func(const T&)>
S ArgTypeAdaptor(T arg) {
return Func(arg);
}

template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return
ElementwiseTensorOp<
complex<T>,
complex<T>,
}

int main()
{

Tensor< complex< float > > x;

conj( x );


}
 
D

Drew McCormack

Drew said:
I have a self written Tensor class which I need to write a number of
elementwise operations for (eg sin, cos, abs, conj).

I am trying to implement most of these in terms of standard library
functions. Unfortunately, not all functions in the standard library are
constructed the same (eg some are template functions, some use
pass-by-value where others use pass by reference). To get around this,
I have tried to come up with an adaptor function. The main routine
looks like this:

template <typename T, typename S, S Func(T)>
Tensor<S> ElementwiseTensorOp( const Tensor<T> &subject ) {
Tensor<S> newTensor(subject.dimensions());
size_t n = subject.size();
S *newData = newTensor.data();
T *subjectData = subject.data();
for ( size_t i = 0; i < n; ++i ) newData = Func(subjectData);
}

I have written an adaptor function that converts pass by reference
functions to pass by value, like this:

template <typename T, typename S, S Func(const T&)>
S ArgTypeAdaptor(T arg) {
return Func(arg);
}

Now I try to use this in my Tensor functions, like so:

template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return
ElementwiseTensorOp<
complex<T>,
complex<T>,
}

This gives me the following error, which I don't understand:

error: no matching function for call to 'ElementwiseTensorOp(const
Periphery::Tensor<std::complex<double> >&)'

I am using gcc 4.0 on Mac OS X. Can anyone explain this to me? Is there
a better way to handle the argument type discrepancies than what I am
doing (eg STL adaptors)?


The following code (derived from your code) compiles fine using gcc
4.0.0. Where is your problem ?

#include <complex>

using namespace std;

template <typename T>
struct Tensor
{
Tensor<T> dimensions() const;
size_t size() const;
T * data();
const T * data() const;
};

template <typename T, typename S, S Func(T)>
Tensor<S> ElementwiseTensorOp( const Tensor<T> &subject ) {
Tensor<S> newTensor(subject.dimensions());
size_t n = subject.size();
S *newData = newTensor.data();
const T *subjectData = subject.data(); // XXXXX - fixed this - XXXXX
for ( size_t i = 0; i < n; ++i ) newData = Func(subjectData);
}



template <typename T, typename S, S Func(const T&)>
S ArgTypeAdaptor(T arg) {
return Func(arg);
}

template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return
ElementwiseTensorOp<
complex<T>,
complex<T>,
}

int main()
{

Tensor< complex< float > > x;

conj( x );


}


Thanks for testing this for me Gianni. It has me even more confused
though, because I don't know why it would work for you, but not for me.
I tried compiling your code separately, and that worked for me too. So
obviously there is something tricky going on.

After some more playing, I was able to get the code to compile by
changing the form of the adaptor, like this:

template <typename T, complex<T> Func(const complex<T>&)>
complex<T> ComplexArgTypeAdaptor(complex<T> arg) {
return Func(arg);
}


template <typename T>
Tensor<complex<T> > conj( const Tensor<complex<T> > &v ) {
return ElementwiseTensorOp<complex<T>, complex<T>,
ComplexArgTypeAdaptor<T, std::conj<T> > >( v );
}

At least it works, but I still don't understand.

Thanks again,
Drew
 

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

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,151
Latest member
JaclynMarl
Top