Sign in to follow this  

unary operator- overload [c++]

This topic is 3864 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm working on something similar to lambda (boost) library, however on a much smaller lever and am trying to overload unary operator-. This is what the relevant code fragment looks like, class a2 { public: a2() { } int operator()(int& x) { return x; } template <class B> Expr<a2, B> operator=(B b) { Expr<a2, B> expression(*this, b, "="); return expression; } a2 operator+(void) const { return *this; } /*int operator-(void) const { return -(*this); }*/ } _1; Anyone got suggestions? :) Or is this too unclear? I can post my whole code in that case... [edit] I'm writing this fragment to make this work > for_each(v.begin(), v.end(), _1 = - _1); [/edit]

Share this post


Link to post
Share on other sites
Quote:

Anyone got suggestions? :)

By applying my considerable powers of deduction based upon that code snippet you provided, I can conclude that your problem is that you have not specified an entry point (in other words, where is main()?) :P

Now, obviously, that's not your real problem and it's not really related at all. So yes, more code would be helpful, in particular:
a) Provide the complete code that stimulates the error(s).
b) Provide the error(s) that are stimulated.

Otherwise, it's hard to tell what's wrong, and what you want fixed.

Your commented-out operator- looks highly suspect because *this is not of type int... it's of type a2. So the return type doesn't match; you're also trying to reapply unary operator-, which is bogus. But without seeing the actual errors and a more complete code transcript, I can't say for sure.

Share this post


Link to post
Share on other sites
Here's my full code from a2.h . My main() contains definition of vector<int> v, and method call for_each(v.begin, v.end(), _1 = -_1);

I've commented operator- in a2 because I can't think of a way around it. Here's my complete code >>

#include <string>
#include <iostream>
#include <ostream>
using namespace std;

//Expr class to evaluate expression
template <class A, class B>
class Expr {

public:
A l_v; // Left Value
B r_v; // Right Value
string Op; // Operator

//Constuctor with no parameters
Expr() { }

Expr(A l, B r, string o) {
l_v = l;
r_v = r;
Op = o;
}

int operator()(int &);
};


//class a2 as a placeholder/expression call for _1
class a2 {

public:
a2() {
}

int operator()(int& x) {
return x;
}

template <class B> Expr<a2, B> operator=(B b) {
Expr<a2, B> expression(*this, b, "=");
return expression;
}

a2 operator+(void) const {
return *this;
}

/*int operator-(void) const {
return ?;
}*/

};

int clarifyExpr(int x, int y) {
return x;
}

int clarifyExpr(a2 a, int x) {
return x;
}

template <class A, class B> int clarifyExpr(Expr<A,B> expression, int x) {
return eval(expression, x);
}

//Evaluation of the given expression
template <class A, class B>
int eval(Expr<A,B> expression, int &x) {
int var;
int l_v;
int r_v;

if(expression.Op != "<<") {
l_v = clarifyExpr(expression.l_v, x);
r_v = clarifyExpr(expression.r_v, x);
if(expression.Op == "+") {
var = l_v + r_v;
} else if(expression.Op == "-") {
var = l_v - r_v;
} else if(expression.Op == "/") {
var = l_v / r_v;
} else if(expression.Op == "*") {
var = l_v * r_v;
} else if(expression.Op == "=") {
x = r_v;
}

}
return var;
}

ostream& clarifyExprForOut(ostream& os, int x) {
return os;
}

template <class A, class B> int Expr<A, B> :: operator()(int &x) {
return eval(*this, x);
}

template <class A, class B> int ExprForOut<A,B> :: operator()(int &x) {
return evalOut(*this, x);
}

template <class A, class B> Expr <A,B> operator+(A a, B b) {
Expr <A, B> expression(a, b, "+");
return expression;
}

template <class A, class B> Expr <A, B> operator-(A a, B b) {
Expr <A, B> expression(a, b, "-");
return expression;
}

template <class A, class B> Expr <A, B> operator*(A a, B b) {
Expr <A, B> expression(a, b, "*");
return expression;
}

template <class A, class B> Expr <A, B> operator/(A a, B b) {
Expr <A, B> expression(a, b, "/");
return expression;
}

//explicit placeholder definition for _1
a2 _1;

Share this post


Link to post
Share on other sites
Well the problem looks pretty obvious to me. Your unary minus operator is simply calling unary minus operator on itself. Thus you have an infinite loop!
Oh, and the return type should possibly be a2, not int.

I see you're using expression templates. Good luck with that!

Share this post


Link to post
Share on other sites
Thanks for the luck.. I haven't made much progress though. I can' t return a2 with a negative value off stack. Thats why I'm completely confused.. In fact I'm looking for any possible suggestions, because I know the lines I'm thinking on is probably completely incorrect.. :(

Share this post


Link to post
Share on other sites
Quote:
In fact I'm looking for any possible suggestions, because I know the lines I'm thinking on is probably completely incorrect.. :(


Ok, its not to bad but there are a number of things which would simplify it lots.

1) Move the operators out of the decleration of a2, this becomes particularly important when you start to do more complicated expressions such as _1 = _2 + 3 * _4, As it stands you would have to write operator overloads for each placeholder (_1, _2, ...) and the result of adding multiplying etc...

2) Maintain some extra type information, currently no longer have acess to the operation at compile time once youve created Expr.

For example:

// note the following is untested and may contain errors
// (missing typenames and such)

template<typename Op, typename Value>
struct unary_op
{
Value value;
unary_op(Value value) : value(value) {}

BOOST_TYPEOF(Op::eval(value()) operator()()
{
return Op::eval(value());
}

// the *NULL is valid because the expression is never evaluated
template<typename T0>
BOOST_TYPEOF(Op::eval(value(*static_cast<T0*>(0))) operator()(T0 t0)
{
return Op::eval(value(t0));
}

// more operator() overloads which just pass there arguments to value
// (i.e. value(arg1, ..., argn))
};

template<typename Op, typename LHS, typename RHS>
struct binary_op
{
LHS lhs;
RHS rhs;
binary_op(LHS lhs, RHS rhs): lhs(lhs), rhs(rhs) { }

BOOST_TYPEOF(Op::eval(lhs(), rhs())) operator()()
{
return Op::eval(lhs(), rhs());
}

template<typename T0>
BOOST_TYPEOF(Op::eval(lhs(*static_cast<T0*>(0)), rhs(*static_cast<T0*>(0))))
operator()(T0 t0)
{
return Op::eval(lhs(t0), rhs(t0));
}

// more operator() overloads that pass there args to lhs and rhs
};

struct negate_op
{
template<typename T>
static BOOST_TYPEOF(-(*static_cast<T*>(0))) eval(T t)
{
return -t;
}
};

struct add_op
{
template<typename T0, typename T1>
static BOOST_TYPEOF((*static_cast<T0*>(0)) + (*static_cast<T1*>(0)))
eval(T0 t0, T1 t1)
{
return t0 + t1;
}
};

// you need to provide stuff to convert int, float, etc to
// lambda_expression< fundamental_wrapper<int> >, etc
// fundamental wrapper should have operator() overloads that just
// return the value it was constructed with ignoring all paramaters
template<typename T>
struct lambda_expression
{
T value;
lambda_expression(T value): value(value) { }

BOOST_TYPEOF(value()) operator()()
{
return value();
}

BOOST_TYPEOF(value(*static_cast<T0*>(0))) operator()(T0 t0)
{
return value(t0);
}

// ......
};

template<typename LHS, typename RHS>
lambda_expression
<
binary_op
<
add_op,
LHS,
RHS
>
>
operator+(lambda_expression<LHS> lhs, lambda_expression<RHS> rhs)
{
return lambda_expression
<
binary_op
<
add_op,
LHS,
RHS
>
>
(
binary_op<add_op, LHS, RHS>(lhs.value, rhs.value)
);
}

template<typename T>
lambda_expression< unary_op<negate_op, T> > operator-(lambda_expression<T> value)
{
return lambda_expression< unary_op<negate_op, T> >
(unary_op<negate_op, T>(value.value));
}

struct place_holder_1 : public
lambda_expression<place_holder_1>
{
template<typename T0>
T0 operator()(T0 t0)
{ return t0; }

template<typename T0, typename T1>
T0 operator()(T0 t0, T1 t1)
{ return t0; }

// ........
};

namespace
{
place_holder_1 _1;
}

// Now this is valid
int main()
{
std::vector<int> my_ints;
/* fill the vector */
std::for_each(my_ints.begin(), my_ints.end(), _1 + 4 + (-_1));
}



The main thing thats missing there is operator= but it would simply return a lambda_expression< binary_op<assign_op, LHS, RHS> > and assign_op would assign its right argument to operator() to its left, doing that would require you change some of the template paramaters to be by reference ofcoarse.

If theres anything you want me to explain in more detail just let me know.

Share this post


Link to post
Share on other sites
Thanks for that.. I was just playing around with templates and your comments make good sense. I need to re-structure it a bit.

And I got the unary operator- going..

Just did,
Expr<A,B> operator-(void) {
Expr<A,B> expression(0,*this,"-");
return expression;
}

Again, thanks to all those who took time to read this and thanks julian. Just getting used to templates, they are sharp.

Share this post


Link to post
Share on other sites

This topic is 3864 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this