f



Template function type for arithmetic operators for elementary types

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< ::operator+=<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::operator+=(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,

-- 
Lionel B


0
me4 (19624)
3/2/2005 10:42:24 AM
comp.lang.c++ 49423 articles. 7 followers. Post Follow

5 Replies
395 Views

Similar Articles

[PageSpeed] 10

Lionel B wrote:
> [...]
> 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
0
v.Abazarov (13256)
3/2/2005 2:06:56 PM
Lionel B wrote:
> 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< ::operator+=<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.


0
gi2nospam (1236)
3/2/2005 2:09:43 PM
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:
ElementWise<MinusEqual>( rhs );

>         return * this;
>     }
> };
0
gi2nospam (1236)
3/2/2005 3:26:22 PM
"Gianni Mariani" <gi2nospam@mariani.ws> wrote in message
news:Y9ydncLXa9a1VLjfRVn-rw@speakeasy.net...
> Lionel B wrote:
> > 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< ::operator+=<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).
>
> /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/

> > // ----- 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.

Yup - that's my solution above.

> > So is it at all possible to use arithmetic operators for elementary
> > types as template arguments?

So... no.

> > 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.

No doubt.

Thanks,


0
me4 (19624)
3/2/2005 5:33:37 PM
Lionel B wrote:

....
> 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;
>     }
> };


If all you need is int support, you're OK, the solution I posted will 
support any type.

> 
> 
>>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() ...

OK - then you're all set.

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

0
gi_a2n (4)
3/3/2005 12:30:17 PM
Reply: