Template function type for arithmetic operators for elementary types

L

Lionel B

Greetings,

I am trying to implement "element-wise" arithmetic operators for a class
along the following lines (this is a simplified example):

// ----- BEGIN CODE -----

struct X
{
int a,b;

typedef int& optype(int&,int); // ???

template<optype OP> void element_wise(X& x)
{
OP(a,x.a);
OP(b,x.b);
}

X& operator+=(X& x)
{
element_wise< ::eek:perator+=<int> >(x); // ??? (line 15)
return *this;
}
};

int main()
{
X x,y;

x.a = 1;
x.b = 2;
y.a = 3;
y.b = 4;

x += y;

return 0;
}

// ----- END CODE -----

I get the error (gcc):

test.cpp: In member function `X& X::eek:perator+=(X&)':
test.cpp:15: error: no matching function for call to
`X::element_wise(X&)'

This is perhaps not surprising, in view of that:

// ----- BEGIN CODE -----

int main()
{
int a = 1;

operator += (a,1);

return 0;
}


// ----- END CODE -----

fails to compile with "error: `operator+=' not defined" (this surprised
me somewhat). It seems that function-style prototypes for arithmetic
operators on elementary types don't exist.

So is it at all possible to use arithmetic operators for elementary
types as template arguments? A simple workaround is to wrap the
operators in a function, but it would be neater (and conceivably more
efficient) not to have to do this.

Regards,
 
V

Victor Bazarov

Lionel said:
[...]
So is it at all possible to use arithmetic operators for elementary
types as template arguments? A simple workaround is to wrap the
operators in a function, but it would be neater (and conceivably more
efficient) not to have to do this.

Take a look at the library implementation of 'std::plus' and other
arithmetic functors. They are defined in <functional> and described
in 20.3.2. My guess is you should simply use them and/or provide your
own of similar form.

V
 
G

Gianni Mariani

Lionel said:
Greetings,

I am trying to implement "element-wise" arithmetic operators for a class
along the following lines (this is a simplified example):

// ----- BEGIN CODE -----

struct X
{
int a,b;

typedef int& optype(int&,int); // ???

template<optype OP> void element_wise(X& x)
{
OP(a,x.a);
OP(b,x.b);
}

X& operator+=(X& x)
{
element_wise< ::eek:perator+=<int> >(x); // ??? (line 15)
return *this;
}
};

Not all compilers will support this yet because of the template-template
parameter. This compiled on GCC 4.0(snapshot).

template < template <typename Tf> class F, typename T >
void Do( T & res, const T& val )
{
F<T>::DoThing( res, val );
}




template <typename Tf>
struct PlusEqual
{
static void DoThing( Tf & res, const Tf & val )
{
res += val;
}
};


template <typename Tf>
struct MinusEqual
{
static void DoThing( Tf & res, const Tf & val )
{
res -= val;
}
};


struct X
{
float a;
int b;


template < template <typename Tf> class F >
void ElementWise( const X & rhs )
{
Do<F>( a, rhs.a );
Do<F>( b, rhs.b );
}


X& operator+=( const X& rhs )
{
ElementWise<PlusEqual>( rhs );
return * this;
}


X& operator-=( const X& rhs )
{
ElementWise<PlusEqual>( rhs );
return * this;
}
};

I don't know how useful this is since it's limited in utility, however I
think that does what you were trying to do. In the example you posted,
there were numerous issues, I won't go into the details other than to
say, you can't pass a function as a template parameter in your case
since you don't know what the type of the parameters are, hence you can
pass a template as the template parameter.
int main()
{
X x,y;

x.a = 1;
x.b = 2;
y.a = 3;
y.b = 4;

x += y;

return 0;
}

This should now compile.

....
// ----- BEGIN CODE -----

int main()
{
int a = 1;

operator += (a,1);

You're invoking global operator += on two ints:

"ComeauTest.c", line 1: error: nonmember operator requires a parameter
with class
or enum type
int operator +=( int &, int );

You can't override the built-in global operators, but you can create
your own types and define new global operators.
return 0;
}


// ----- END CODE -----

fails to compile with "error: `operator+=' not defined" (this surprised
me somewhat). It seems that function-style prototypes for arithmetic
operators on elementary types don't exist.

So is it at all possible to use arithmetic operators for elementary
types as template arguments? A simple workaround is to wrap the
operators in a function, but it would be neater (and conceivably more
efficient) not to have to do this.

Most compilers I have used will optimize the function calls away and the
efficiency become a non-issue.
 
G

Gianni Mariani

Gianni Mariani wrote:

Correction:

....
template <typename Tf>
struct MinusEqual
{
static void DoThing( Tf & res, const Tf & val )
{
res -= val;
}
};


struct X
{
float a;
int b;
....



X& operator-=( const X& rhs )
{
ElementWise<PlusEqual>( rhs );

Should be:
 
L

Lionel B

Gianni Mariani said:
Not all compilers will support this yet because of the template-template
parameter. This compiled on GCC 4.0(snapshot).

/snip code/

Cheers, yes that works for my gcc 3.3.3 too.
I don't know how useful this is since it's limited in utility, however I
think that does what you were trying to do.

It does. BTW, the reason for what I was trying to do is simply to avoid
code duplication: my "real" ElementWise() function is rather lengthy and
complex, and needs to be parametrised by operator type (plus, minus,
etc.).

I suspect the "functional" approach you give above is probably
uneccessarily sophisticated for my needs... the following works
perfectly well for me.

typedef void optype(int&, const int&);

void plus_equal(int& a, int b)
{
a += b;
}

struct X
{
int a,b;

template<optype OP> void element_wise(X& x)
{
OP(a,x.a);
OP(b,x.b);
}

X& operator+=(X& x)
{
element_wise<plus_equal>(x);
return *this;
}
};
In the example you posted,
there were numerous issues, I won't go into the details other than to
say, you can't pass a function as a template parameter in your case
since you don't know what the type of the parameters are

Not sure I follow you... I *do* know the parameter types of the function
I want to pass as template parameter: namely (int&, const int), as
above. My issue was whether I could pass the global operator+= function
as a parameter to my to element_wise() ...
/snip/

You're invoking global operator += on two ints:

"ComeauTest.c", line 1: error: nonmember operator requires a parameter
with class
or enum type
int operator +=( int &, int );

You can't override the built-in global operators, but you can create
your own types and define new global operators.

Yup - that's my solution above.

So... no.
Most compilers I have used will optimize the function calls away and the
efficiency become a non-issue.

No doubt.

Thanks,
 
G

Gianni Mariani

Lionel B wrote:

....
I



It does. BTW, the reason for what I was trying to do is simply to avoid
code duplication: my "real" ElementWise() function is rather lengthy and
complex, and needs to be parametrised by operator type (plus, minus,
etc.).

I suspect the "functional" approach you give above is probably
uneccessarily sophisticated for my needs... the following works
perfectly well for me.

typedef void optype(int&, const int&);

void plus_equal(int& a, int b)
{
a += b;
}

struct X
{
int a,b;

template<optype OP> void element_wise(X& x)
{
OP(a,x.a);
OP(b,x.b);
}

X& operator+=(X& x)
{
element_wise<plus_equal>(x);
return *this;
}
};


If all you need is int support, you're OK, the solution I posted will
support any type.
Not sure I follow you... I *do* know the parameter types of the function
I want to pass as template parameter: namely (int&, const int), as
above. My issue was whether I could pass the global operator+= function
as a parameter to my to element_wise() ...

OK - then you're all set.

I thought you were looking for a more generic solution. Good luck.
 

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,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top