Even after years C++ is confusing the hell out of me..
My class implements
virtual CStatCounter& operator= (CStatCounter const& inSC);
and
virtual CStatCounter operator+(const CStatCounter& rhs);
And I'm keeping a
vector<CStatCounter*> mStatistics
somewhere else. Now all I'm trying to do is accumulate all values.
After being laughed at by std::accumulate I've switched to a simple loop rolled on my own, still no luck:
CStatCounter *iniCounter = new CStatCounter(0);
BOOST_FOREACH (CStatCounter *counter, mStatistics)
{
iniCounter = iniCounter+counter;
}
The compiler (Xcode 4.2/clang) complains about
Invalid operands to binary expression ('CStatCounter *' and 'CStatCounter *')
I can change the loop body to counter+counter and it still fails with the same error message.
Shouldn't it be smart enough to implicitly convert between references and pointers?
Am I missing something trivial here?
Shouldn't it be smart enough to implicitly convert between references
and pointers?
It could, but that wouldn't be C++, would it? When you can overload operators for every conceivable combination of operands, it's really not safe to make such assumptions.
Am I missing something trivial here?
Dereferencing:
*iniCounter = *iniCounter + *counter;
By the way, you can still use std::accumulate, you just need a custom binary operation, like this:
CStatCounter MyAddFunc(const CStatCounter & lhs, const CStatCounter * rhsp)
{
return lhs + *rhsp;
}
*iniCounter = std::accumulate(mStatistics.begin(), mStatistics.end(),
*iniCounter, MyAddFunc);
How about *iniCounter = *iniCounter + *counter;?
On a side note, are you sure all those pointers and virtuals are really necessary?
There is no implicit conversion here.
You will have to either provide exact overloads which you make use of.
virtual bool operator+(const CStatCounter* rhs);
virtual CStatCounter& operator= (CStatCounter const* inSC);
or modify your code to match the overloads you provided.
*iniCounter = *iniCounter + *counter;
Related
I have a weird error when I try to compile this piece of code.
I will explain my problem.
I defined a vector2D as following:
typedef struct LX_Vector2D
{
float vx;
float vy;
LX_Vector2D& operator =(const LX_Vector2D v); // Defined
} LX_Vector2D;
I also defined two operators on this vector:
bool operator ==(LX_Vector2D& u,LX_Vector2D& v); // Are u and v equal?
LX_Vector2D operator -(LX_Vector2D& u); // Get the opposite vector
All of these overloaded operators was defined.
So I tested these operators in the following code:
LX_Vector2D u = {3.14,-2.56};
LX_Vector2D expected_vec = {-u.vx,-u.vy};
if(expected_vec == (-u)) // ERROR
cout << "OK" << endl;
else
cout << "NO" << endl;
When I compile this code, I have this error:
no match for ‘operator==’ in ‘expected_vec == operator-((* & u))‘
I have no problem with '=' and '==' because I defined and tested them before I implemented '-'.
But when I modify this code to get this:
u = -u;
if(expected_vec == u) // OK
I have no error.
I do not understand that, because it seems these two pieces of code are semantically identical.
Here is the definition of operator '-':
LX_Vector2D operator -(LX_Vector2D& u)
{
return {-u.vx,-u.vy};
}
So my question is:
Why doesn't my compiler recognize ‘expected_vec == (-u)‘ as a call of operator '==' with expected_vec and (-u) as parameters?
Another question:
How can I have the possibility to use if(expected_vec == (-u)) without any problem, if it is possible?
I use g++ 4.6.1.
The problem here is that the result from operator- when used as part of another expression is a temporary value, and that operator== takes non-constant references. A non-constant reference can't bind to a temporary value.
The simple solution? Make the operator== function take constant references:
bool operator ==(const LX_Vector2D& u, const LX_Vector2D& v)
// ^^^^^ ^^^^^
// Note the use of `const`
As a general recommendation, when declaring functions that will not modify their arguments, always pass the arguments as constant. It will avoid problems like this, and may also help the compiler with possible optimizations.
Operator - returns a temporary object:
LX_Vector2D operator -(LX_Vector2D& u)
while your comparison operator accepts a non-const reference:
bool operator ==(LX_Vector2D& u,LX_Vector2D& v)
Temporary objects, like returned by the - operator, cannot be used as non-const references. It's not allowed because there is no purpose modifying an object that is about to go out of scope anyway, so the compiler makes sure you don't even attempt it.
As a general rule, you should make any function that does not modify its arguments take const references instead, especially comparison functions:
bool operator ==(const LX_Vector2D& u,const LX_Vector2D& v)
in addition to the other answers, your assignment operator should also take a const& as in:
LX_Vector2D& operator =(const LX_Vector2D& v)
note the & after the parameter type.
As a general rule, and to avoid the construction of unnecessary copies of objects, parameters of complex types should almost always be const & if you are not planning on changing the parameter instance. Or if you are planning on changing the parameter instance, then simply as a reference, i.e., &.
I have a couple of pure virtual classes, Matrix and Vector. Throughout my code base I try to only create dependencies on them and not their concrete subclasses e.g. SimpleTransformationMatrix44 and SimpleTranslationVector4. The motivation for this is that I can use third party (adapted) classes in place of mine without much trouble.
I would like to overload the arithmetic operators (sourced from here):
T T::operator +(const T& b) const;
T T::operator -(const T& b) const;
T T::operator *(const T& b) const;
I want to declare them in the pure virtual classes so that it is valid to perform the operations on references/pointers to them, the problem being that an abstract class cannot be returned by value. The best solution I can think of is something like this:
std::unique_ptr<T> T::operator +(const T& b) const;
std::unique_ptr<T> T::operator -(const T& b) const;
std::unique_ptr<T> T::operator *(const T& b) const;
Which allows this (without down casts!):
std::unique_ptr<Matrix> exampleFunction(const Matrix& matrix1, const Matrix& matrix2)
{
std::unique_ptr<Matrix> product = matrix1 * matrix2;
return std::move(product);
}
A pointer seems to be the only option in this case since returning a value is invalid and returning a reference is just plain silly.
So I guess my question is: Have I gone off the plot with this idea? If you saw it in some code you were working on would you be thinking WTF to yourself? Is there a better way to achieve this?
First off: Overloading operators is something that applies best to value types. As you have found out, polymorphism doesn't play well with it. If you are willing to walk on crutches, this might help, though:
If you follow the advice of Stackoverflow's operator overloading FAQ, you will implement operator+() as a non-member atop of operator+=(). The latter returns a reference. It's still a problem, because it can only return a base class reference, but as long as you only use it for expressions expecting that, you are fine.
If you then templatize operator+() as DeadMG suggested, you might be able to do what you want:
template<typename T>
T operator+(const T lhs, const T& rhs)
{
lhs += rhs;
return lhs;
}
Note that this would catch any T for which no better-matching operator+() overload can be found. (This might seem like a good idea — until you forget to include a header and this operator catches the x+y, making the code compile, but silently produce wrong results.) So you might want to restrict this.
One way would be to put it into the same namespace as you matrix and vector types. Or you use a static_assert to ensure only types derived from the two are passed in.
Have I gone off the plot with this idea?
Yes. The appropriate solution to this problem is to implement flexibility via template, not inheritance. Inheritance is most definitely not suited to this kind of problem. In addition, it's usual (if not mandated) to have the dimensions of the vector or matrix specified as a template parameter in addition, instead of at run-time.
I'm compiling some c++ code of a class MegaInt which is a positive decimal type class that allows arithmetic operations on huge numbers.
I want to overload operator bool to allow code like this:
MegaInt m(45646578676547676);
if(m)
cout << "YaY!" << endl;
This is what I did:
header:
class MegaInt
{
public:
...
operator bool() const;
};
const MegaInt operator+(const MegaInt & left, const MegaInt & right);
const MegaInt operator*(const MegaInt & left, const MegaInt & right);
implementation:
MegaInt::operator bool() const
{
return *this != 0;
}
const MegaInt operator+(const MegaInt & left, const MegaInt & right)
{
MegaInt ret = left;
ret += right;
return ret;
}
Now, the problem is if I do:
MegaInt(3424324234234342) + 5;
It gives me this error:
ambiguous overload for 'operator+' in 'operator+(const MegaInt&, const MegaInt&)
note: candidates are: operator+(int, int) |
note: const MegaInt operator+(const MegaInt&, const MegaInt&)|
I don't know why. How is the overloaded bool() causing operator+ to become ambiguous?¸
Thank You.
Well, everyone gave me great answers, unfortunately, none of them seem to solve my problem entirely.
Both void* or the Safe Bool Idiom works. Except for one tiny problem, I hope has a workaround:
When comparing with 0 like:
if (aMegaInt == 0)
The compiler gives an ambiguous overload error again. I understand why: it doesn't know if we're comparing to false or to MegaInt of value 0. None the less, in that case, I'd want it to cast to MegaInt(0). Is there a way to force this?
Thank You Again.
The C++ compiler is allowed to automatically convert bool into int for you, and that's what it wants to do here.
The way to solve this problem is to employ the safe bool idiom.
Technically, creating an operator void* is not an example of the safe bool idiom, but it's safe enough in practice, because the bool/int problem you're running into is a common error, and messes up some perfectly reasonable and otherwise correct code (as you see from your question), but misuses of the void* conversion are not so common.
The wikipedia entry on explicit conversion operators for C++0x has a decent summary of why you see this error pre-C++0x. Basically, the bool conversion operator is an integral conversion type, so it will be used in an integral arithmetic expression. The pre-C++0x fix is to instead use void * as the conversion operator; void * can be converted to a boolean expression, but not to an integral expression.
As Erik's answer states, the problem here is that by providing an implicit conversion to bool you are opening the door to expressions that can mean multiple things; in this case the compiler will complain of ambiguity and give your an error.
However, note that providing an implicit conversion to void* will not let you off the hook; it will just change the set of expressions which present a problem.
There are two airtight solutions to this issue:
Make the conversion to bool explicit (which can be undesirable if the class represents an entity with an intuitive "true/false" value)
Use the safe bool idiom (this really covers all bases, but as many good things in life and C++ is way too complicated -- you pay the price)
The problem is that bool can freely convert to int. So the expression MegaInt(3424324234234342) + 5; can equally validly be interpreted this way:
(bool)(MegaInt(3424324234234342)) + 5;
or:
MegaInt(3424324234234342) + MegaInt(5);
Each one of those expressions involves one user defined conversion and are equal in the eyes of the compiler. Conversion to bool is highly problematic for this reason. It would be really nice to have a way to say it should only happen in a context that explicitly requires a bool, but there isn't. :-/
The conversion to void * that someone else suggests is a workaround, but I think as a workaround it has problems of its own and I wouldn't do it.
MegaInt(3424324234234342) + 5;
MegaInt + int;
Should the compiler convert your MegaInt to an integral (bool is an integral type) or the integer to MegaInt (you have an int constructor)?
You fix this by creating an operator void * instead of an operator bool:
operator void *() const { return (*this != 0) ? ((void *) 1) : ((void *) 0); }
Others have mentioned the Safe Bool Idiom. However, for objects like yours it is a bad idea to add all this nasty, special logic when you want full algebra support anyway.
You're defining a custom integer type. You get far more for your effort by defining "operator==" and "operator!=", then implementing "operator bool()" as something like:
operator bool()
{
return (*this != 0);
}
Just from those 3 functions you get all of the "if" idioms for integers, and they'll behave the same for your custom ints as the built-in ones: "if(a==b)", "if(a!=b)", "if(a)", "if(!a)". Your implicit "bool" rule will also (if you're careful) work intuitively as well.
Besides, the full "Safe Bool Idiom" is unnecessary. Think about it- the only time you need it is "1) comparison of 2 objects is ill-defined or undefined, 2) cast to (int) or other primitive types needs to be protected and 3) object validity IS well-defined (the actual source of the returned bool)."
Well, 2) is only a consideration if you actually wish to SUPPORT casting to a numeric type like int or float. But for objects that have NO well-defined notion of equality (# 1), providing such casts unavoidably creates the risk of the very "if(a==b)" logic bombs the idiom supposedly protects you from. Just declare "operator int()" and such private like you do with the copy ctor on non-copyable objects and be done with it:
class MyClass {
private:
MyClass(const MyClass&);
operator int();
operator long();
// float(), double(), etc. ...
public:
// ctor & dtor ..
bool operator==(const MyClass& other) const { //check for equality logic... }
bool operator!=(const MyClass& other) const { return !(*this == other); }
operator bool() { return (*this != 0); }
};
The copy assignment operator has the usual signature:
my_class & operator = (my_class const & rhs);
Does the following signature have any practical use?
my_class const & operator = (my_class const & rhs);
You can only define one or the other, but not both.
The principle reason to make the return type of copy-assignment a non-const reference is that it is a requirement for "Assignable" in the standard.
If you make the return type a const reference then your class won't meet the requirements for use in any of the standard library containers.
Don't do that. It prevent a client from writing something like:
(a = b).non_const_method();
instead of the longer form:
a = b;
a.non_const_method();
While you may not like the shorthand style, it's really up to the user of the library to decide how they want to write the code.
An answer that mirrors one from Overloading assignment operator in C++:
Returning a const& will still allow assignment chaining:
a = b = c;
But will disallow some of the more unusual uses:
(a = b) = c;
Note that this makes the assignment operator have semantics similar to what it has in C, where the value returned by the = operator is not an lvalue. In C++, the standard changed it so the = operator returns the type of the left operand, so the result is an lvalue. But as Steve Jessop noted in a comment to another answer, while that makes it so the compiler will accept
(a = b) = c;
even for built-ins, the result is undefined behavior for built-ins since a is modified twice with no intervening sequence point. That problem is avoided for non-builtins with an operator=() because the operator=() function call serves as a sequence point.
I see no problem returning a const& unless you want to specifically allow the lvalue semantics (and design the class to ensure it acts sensibly with those semantics). If you're users want to do something unusual with the result of operator=(), I'd prefer that the class disallow it rather than hope it gets it right by chance instead of design.
Also. note that while you said:
You can only define one or the other, but not both.
that's because the function signature in C++ doesn't take into account the return value type. You could however have multiple operator=() assignement operatiors that take different parameters and return different types appropriate to the parameter types:
my_class& operator=( my_class& rhs);
my_class const& operator=(my_class const& rhs);
I'm not entirely sure what this would buy you though. The object being assigned to (that is presumably the reference being returned) is non-const in both cases, so there's no logical reason to return a const& just because the righ-hand-side of the = is const. But maybe I'm missing something...
Effective C++ explains that this would break compatibility with the built-in types of C++.
You can do this with plain ints:
(x = y) = z;
so he reasons, however silly this looks like, one should be able to do the same with one's own type as well.
This example is there in 2nd Edition, although not anymore in the 3rd. However, this quote from 3rd Ed., Item 10 tells the same still:
[...] assignment returns a reference to its left-hand argument, and that's the convention you should follow when you implement assignment operators for your classes:
class Widget {
public:
...
Widget& operator=(const Widget& rhs) // return type is a reference to
{ // the current class
...
return *this; // return the left-hand object
}
...
};
Why is everyone obsessing over (a = b) = c? Has that ever been written by accident?
There is probably some unforeseen utility of the result of assignment being altered. You don't just make arbitrary rules against made-up examples that look funny. Semantically there is no reason that it should be const, so do not declare it const for lexical side effects.
Here is an example of somewhat reasonable code that breaks for const & assignment:
my_class &ref = a = b;
As in any other usage of const, const is the default, unless you really want to let the user change.
Yes, it should be const. Otherwise clients can do this:
class MyClass
{
public:
MyClass & operator = (MyClass const & rhs);
}
void Foo() {
MyClass a, b, c;
(a = b) = c; //Yikes!
}
If I've overloaded operator+ and operator= do I still need to overload
operator+= for something like this to work:
MyClass mc1, mc2;
mc1 += mc2;
Yes, you need to define that as well.
A common trick however, is to define operator+=, and then implement operator+ in terms of it, something like this:
MyClass operator+ (MyClass lhs, const MyClass& rhs){
return lhs += rhs;
}
If you do it the other way around (use + to implement +=), you get an unnecessary copy operation in the += operator which may be a problem i performance-sensitive code.
operator+= is not a composite of + and =, therefore you do need to overload it explicitly, since compiler do not know to build puzzles for you. but still you do able to benefit from already defined/overloaded operators, by using them inside operator+=.
Yes, you do.
If the real question here is, "I don't want to write a load of repetitive operators, please tell me how to avoid it", then the answer may be:
http://www.boost.org/doc/libs/1_38_0/libs/utility/operators.htm
The syntax looks a little fiddly, though. As I've never used it myself, I can't reassure you that it's simple really.