Confusion in overloading the assignment operator = [duplicate] - c++

When defining an assignment operator, it invariably looks like this:
class X {...};
X& X::operator=(...whatever...);
That is, it has the return type "reference to X". Here, parameters (...whatever...) can be X&, const X&, just X when using the copy-and-swap idiom, or any other type.
It seems strange that everyone recommends returning a non-const reference to X, regardless of the parameters. This explicitly allows expressions like (a = b).clear(), which is supposed to be good.
I have a different opinion, and I want to disallow expressions like (x=y).clear, (x=y)=z, and even x=y=z in my code. My idea is that these expressions do too complex things on a single line of code. So I decided to have my assignment operators return void:
void X::operator=(X) {...}
void X::operator=(int) {...}
Which negative effects does this have? (except looking different than usual)
Can my class X be used with standard containers (e.g. std::vector<X>)?
I am using C++03 (if that matters).

Your class does not meet the CopyAssignable concept (§17.6.3.1) so it is no longer guaranteed by the standard to work with the standard containers that require this (e.g. std::vector requires this for insert operations).
Besides that, this behavior is not idiomatic and will be perceived as surprising by programmers using your code. If you want to disallow chaining, consider adding a named function that does the assignment instead.
Just don't try to change the behavior of idiomatic operators in subtle ways like this. It will make your code harder to read and maintain.

Related

Why does std::lerp not work with any type that has implemented required operations?

After learning about std::lerp I tried to use it with strong types, but it fails miserably since it only works for built in types...
#include <iostream>
#include <cmath>
struct MyFloat{
float val = 4.7;
MyFloat operator *(MyFloat other){
return MyFloat(other.val*val);
}
MyFloat operator +(MyFloat other){
return MyFloat(other.val+val);
}
MyFloat operator -(MyFloat other){
return MyFloat(other.val-val);
}
};
int main()
{
MyFloat a{1}, b{10};
//std::lerp(a, b, MyFloat{0.3}); :(
std::lerp(a.val, b.val, 0.3f);
}
My question is:
Is there a good reason why C++20 introduced a function/algorithm that is not generic?
It would be impossible for std::lerp to provide its guarantees about numerical behavior for arbitrary types that happen to provide some arithmetic operators. (There’s no way for the library to detect that your example merely forwards them to the builtin float versions.)
While requirements could be imposed on the parameter type to allow a correct implementation, they would need to be exceedingly detailed for MyFloat to be handled with the same performance and results as float. For example, the implementation may need to compare values of the parameter type (which your type doesn’t support!) and can capitalize on the spacing between floating-point values to provide monotonicity guarantees near t=1.
Since those guarantees are the entire point of the function (the naïve formulas are trivial), it’s not provided at all in a generic form.
Is there a good reason why C++20 introduced a function/algorithm that is not generic?
Implementing it for a small set of types makes it easier to ensure correct results when mixing different argument types and dealing with possible implicit conversions (not to mention ambiguous overloads). As the last overload on cppreference (which is likely a template) specifies, the types are adjusted such that as little precision is lost as possible.
How can the same be achieved when the list of types is open ended? And a client programmer injects whatever meaning they want into overloaded operators? I'd say its pretty much impossible.
And it's nothing new, take std::pow for instance, which had a similar overload added to it in C++11. The standard library utilities that deal with numerical data are always specified only for types the implementation is aware of.
If lerp makes sense for your custom type, then you can add overloads into your custom namespace. ADL will find it, and generic code that is build on top of
using std::lerp;
lerp(arg1, arg2, arg3);
can be made to work for your custom type too.

Equality operator overloads: Is (x!=y) == (!(x==y))?

Does the C++ standard guarantee that (x!=y) always has the same truth value as !(x==y)?
I know there are many subtleties involved here: The operators == and != may be overloaded. They may be overloaded to have different return types (which only have to be implicitly convertible to bool). Even the !-operator might be overloaded on the return type. That's why I handwavingly referred to the "truth value" above, but trying to elaborate it further, exploiting the implicit conversion to bool, and trying to eliminate possible ambiguities:
bool ne = (x!=y);
bool e = (x==y);
bool result = (ne == (!e));
Is result guaranteed to be true here?
The C++ standard specifies the equality operators in section 5.10, but mainly seems to define them syntactically (and some semantics regarding pointer comparisons). The concept of being EqualityComparable exists, but there is no dedicated statement about the relationship of its operator == to the != operator.
There exist related documents from C++ working groups, saying that...
It is vital that equal/unequal [...] behave as boolean negations of each other. After all, the world would make no sense if both operator==() and operator!=() returned false! As such, it is common to implement these operators in terms of each other
However, this only reflects the Common Sense™, and does not specify that they have to be implemented like this.
Some background: I'm just trying to write a function that checks whether two values (of unknown type) are equal, and print an error message if this is not the case. I'd like to say that the required concept here is that the types are EqualityComparable. But for this, one would still have to write if (!(x==y)) {…} and could not write if (x!=y) {…}, because this would use a different operator, which is not covered with the concept of EqualityComparable at all, and which might even be overloaded differently...
I know that the programmer basically can do whatever he wants in his custom overloads. I just wondered whether he is really allowed to do everything, or whether there are rules imposed by the standard. Maybe one of these subtle statements that suggest that deviating from the usual implementation causes undefined behavior, like the one that NathanOliver mentioned in a comment, but which seemed to only refer to certain types. For example, the standard explicitly states that for container types, a!=b is equivalent to !(a==b) (section 23.2.1, table 95, "Container requirements").
But for general, user-defined types, it currently seems that there are no such requirements. The question is tagged language-lawyer, because I hoped for a definite statement/reference, but I know that this may nearly be impossible: While one could point out the section where it said that the operators have to be negations of each other, one can hardly prove that none of the ~1500 pages of the standard says something like this...
In doubt, and unless there are further hints, I'll upvote/accept the corresponding answers later, and for now assume that for comparing not-equality for EqualityComparable types should be done with if (!(x==y)) to be on the safe side.
Does the C++ standard guarantee that (x!=y) always has the same truth value as !(x==y)?
No it doesn't. Absolutely nothing stops me from writing:
struct Broken {
bool operator==(const Broken& ) const { return true; }
bool operator!=(const Broken& ) const { return true; }
};
Broken x, y;
That is perfectly well-formed code. Semantically, it's broken (as the name might suggest), but there's certainly nothing wrong from it from a pure C++ code functionality perspective.
The standard also clearly indicates this is okay in [over.oper]/7:
The identities among certain predefined operators applied to basic types (for example, ++a ≡ a+=1) need not hold for operator functions. Some predefined operators, such as +=, require an operand to be an lvalue when applied to basic types; this is not required by operator functions.
In the same vein, nothing in the C++ standard guarantees that operator< actually implements a valid Ordering (or that x<y <==> !(x>=y), etc.). Some standard library implementations will actually add instrumentation to attempt to debug this for you in the ordered containers, but that is just a quality of implementation issue and not a standards-compliant-based decision.
Library solutions like Boost.Operators exist to at least make this a little easier on the programmer's side:
struct Fixed : equality_comparable<Fixed> {
bool operator==(const Fixed&) const;
// a consistent operator!= is provided for you
};
In C++14, Fixed is no longer an aggregate with the base class. However, in C++17 it's an aggregate again (by way of P0017).
With the adoption of P1185 for C++20, the library solution has effectively becomes a language solution - you just have to write this:
struct Fixed {
bool operator==(Fixed const&) const;
};
bool ne(Fixed const& x, Fixed const& y) {
return x != y;
}
The body of ne() becomes a valid expression that evaluates as !x.operator==(y) -- so you don't have to worry about keeping the two comparison in line nor rely on a library solution to help out.
In general, I don't think you can rely on it, because it doesn't always make sense for operator == and operator!= to always correspond, so I don't see how the standard could ever require it.
For example, consider the built-in floating point types, like doubles, for which NaNs always compare false, so operator== and operator!= can both return false at the same time. (Edit: Oops, this is wrong; see hvd's comment.)
As a result, if I'm writing a new class with floating point semantics (maybe a really_long_double), I have to implement the same behaviour to be consistent with the primitive types, so my operator== would have to behave the same and compare two NaNs as false, even though operator!= also compares them as false.
This might crop up in other circumstances, too. For example, if I was writing a class to represent a database nullable value I might run into the same issue, because all comparisons to database NULL are false. I might choose to implement that logic in my C++ code to have the same semantics as the database.
In practice, though, for your use case, it might not be worth worrying about these edge cases. Just document that your function compares the objects using operator== (or operator !=) and leave it at that.
No. You can write operator overloads for == and != that do whatever you wish. It probably would be a bad idea to do so, but the definition of C++ does not constrain those operators to be each other's logical opposites.

Why is it legal to define arbitrary return type of overloaded operators when T or T& is expected

It is a spin off question from the example that Original Poster made in here: Size of objects during Multilevel/Multiple inheritance. I hope this is valid to ask, and I could not find any info on this topic.
Can anyone tell why is this even legal to write stuff like this:
#include <iostream>
using namespace std;
struct A{
int count = 0;
void operator ++(){count++;};
void operator ++(int){count++;};
void operator =(int){};
};
int main() {
A a;
++a;
a++;
a=5;
std::cout << a.count;
return 0;
}
This compiles with g++ -std=c++11 -Wpedantic ./operator_overload.cpp with no warnings at all. (c++11 is added for in-class initializer).
Why is it allowed by standard to return arbitrary types when a objects of the type of original class are expected on return, maybe they references.
My guess is that this allows writing of the expression types and implementation of the lazy evaluation and smart arithmetic optimizations for some classes and it would be hard to guess whether in the end the expression has sense type-wise. IMO it could be checked whether the resulting type of the expression can be casted to T, but I am not sure do not feel confident to make hard assumptions here.
But then I would still like to know why specifically void is allowed, as this seems completely nonsensical to me. Is there any use for it, or is this just left as is not to bloat standard or the compilers' codes?
Like any other overloaded function, operator overloads are looked up by their name and parameter types; the return type is only relevant if the calling code uses it. There are no special rules to require them to act like the built-in operator, either in behaviour or return type.
Such a restriction would further limit the usefulness of operator overloading to define domain-specific syntax (such as << and >> in the standard I/O library, and other (ab)uses in various popular libraries); some might argue that that's a good thing, but others would disagree, and the language doesn't judge.
The only exceptions are for operators used by language constructs, such as -> and new, which must return the right type for expressions using them to be valid. Even then, as noted in the comments with an awesome example, there can be some flexibility in the return type.
A good (IMO) thing to remember is that it is called operator overloading because you overload the meaning, so that ++ doesn't necessarily need to have the same meaning as the builtin ++ operator.
Expression template libraries are an example where it is useful to be able to declare different return types.
Because there is no real reason to forbid that usage. So they let programmer decide if that can be useful, the return type is not part of the overload resolution anyway.
template library like spirit use a lot of "hack" to implement parser directly in code with a EBNF-style grammar syntax and use that freedom.

Macros to disallow class copy and assignment. Google -vs- Qt

To disallow copying or assigning a class it's common practice to make the copy constructor
and assignment operator private. Both Google and Qt have macros to make this easy and visible.
These macros are:
Google:
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
Qt:
#define Q_DISABLE_COPY(Class) \
Class(const Class &); \
Class &operator=(const Class &);
Questions:
Why are the signatures of the two assignment operators different? It seems like the Qt version is correct.
What is the practical difference between the two?
It doesn't matter. The return type is not part of a function's signature, as it does not participate in overload resolution. So when you attempt to perform an assignment, both declarations will match, regardless of whether you use the return type.
And since the entire point in these macros is that the functions will never get called, it doesn't matter that one returns void.
I'd just like to mention that there is an alternative strategy for implementing an abstraction for disallowing copy and assignment of a class. The idea is to use inheritance instead of the preprocessor. I personally prefer this approach as I follow the rule of thumb that it is best to avoid using the preprocessor when at all possible.
boost::noncopyable is an example implementation. It is used as follows:
class A : noncopyable
{
...
};
See Boost.Utility, specifically boost::noncopyable. It's not a macro but a base class with private copy and assignment. It prevents the compiler from generating implicit copy and assignment in derived classes.
edit: Sorry, this was not an answer to the original question. By the way, boost::noncopyable uses a const reference as return type for the assignment operator. I was under the impression that the type of the return value doesn't matter since it's not supposed to be used. Still, making the operator private doesn't prevent usage inside the class or friends in which case a non-usual return type (like void, a const reference, etc) might lead to compilation errors and catch additional bugs.
There's no practical difference. The assignment operator signatures differ just as a matter of style. It's usual to have an assignment operator returning a reference to allow chaining:
a = b = c;
but a version returning void is also legal and will work just fine for cases when the only purpose is to just declare the operator private and therefore prohibited to use.
From the standard, 12.8, clause 9: "A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X&, or const volatile X&." It says nothing about the return type, so any return type is permissible.
Clause 10 says "If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly."
Therefore, declaring any X::operator=(const X&) (or any other of the specified assignment types) is sufficient. Neither the body nor the return type is significant if the operator will never be used.
Therefore, it's a stylistic difference, with one macro doing what we'd likely expect and one saving a few characters and doing the job in a way that's likely to surprise some people. I think the Qt macro is better stylistically. Since we're talking macro, we're not talking about the programmer having to type anything extra, and failing to surprise people is a good thing in a language construct.
Others have already answered why it's legal to have different return values for operator=; IMHO jalf said it best.
However, you might wonder why Google uses a different return type, and I suspect it's this:
You don't have to repeat the type name when disabling the assignment operator like this. Usually the type name is the longest part of the declaration.
Of course, this reason is void given that a macro is used but still - old habits die hard. :-)
Both serve the same purpose
Once you write this one:
Class &operator=(const Class &);
you will get the benefits of chain assignments. But in this case you want the assignment operator to be private. so it doesn't matter.
Qt version is backward compatible, while google's is not.
If you develop your library and deprecate the use of assignment before you completely remove it, in Qt it will most likely retain the signature it originally had. In this case older application will continue to run with new version of library (however, they won't compile with the newer version).
Google's macro doesn't have such a property.
As several other answers have mentioned, the return type of the function doesn't participate in the function signature, so both declarations are equivalent as far as making the assignment operator unusable by clients of the class.
Personally I prefer the idiom of having a class privately inherit from an empty non-copyable base class (like boost::noncopyable, but I have my own so I can use it in projects that don't have boost available). The empty base class optimization takes care of making sure there's zero overhead, and it's simple, readable, and doesn't rely on the dreaded preprocessor macro functionality.
It also has the advantage that copy and assignment can't even be used within class implementation code - it'll fail at compile time while these macros will fail at link time (likely with a less informative error message).
Incidentally, if you have access to the Boost libraries (You don't? Why the heck not??), The Utility library has had the noncopyable class for a long time:
class YourNonCopyableClass : boost::noncopyable {
Clearer IMHO.
In practice I would say that both should not be used anymore if you have a C++11 compiler.
You should instead use the delete feature , see here
Meaning of = delete after function declaration
and here
http://www.stroustrup.com/C++11FAQ.html#default
Why : essentially because compiler message is much more clearer. When the compiler need one of the copy or copy assignment operator, it immediately points out to the line where the =delete was coded.
Better and complete explanations can also be found in Item 11: Prefer deleted functions to private undefined ones from Effective Modern C++ book by Scott Meyers

An operator == whose parameters are non-const references

I this post, I've seen this:
class MonitorObjectString: public MonitorObject {
// some other declarations
friend inline bool operator==(/*const*/ MonitorObjectString& lhs,
/*const*/ MonitorObjectString& rhs)
{ return lhs.fVal==rhs.fVal; }
}
Before we can continue, THIS IS VERY IMPORTANT:
I am not questioning anyone's ability to code.
I am just wondering why someone would need non-const references in a comparison.
The poster of that question did not write that code.
This was just in case. This is important too:
I added both /*const*/s and reformatted the code.
Now, we get back to the topic:
I can't think of a sane use of the equality operator that lets you modify its by-ref arguments. Do you?
Perhaps the classes use a form of lazy initialization. When the data is accessed, proper initialization must occur, and the data must be fetched. This may change class members.
However, lazy initialization can be formed so that modification to the class isn't necessary. This can be accomplished by using the Pimpl idiom (by a pointer to a private class) or by using the mutable keyword (not recommended!).
Most likely they forgot the const.
Operator overloads should behave consistently and not perform 'out of character' actions.
As a general rule, an equality operator should never modify any of the objects it is comparing. Declaring const enforces this at the compiler level. However, it is often left out. "Const correctness" is very often overlooked in C++.
There's a more baffling problem with the issue you bring up.
If I have two MonitorObjectStrings that are already const, I can't use this equality function.
There's clearly no requirement for non-const args in this case and, like you, I wouldn't think there's any general case for it either.
However, it's certainly the case that const-correctness problems can push their way up from lower levels of the code, and if you can't correct them low-down, then you might have to work around them higher up. Perhaps that's what happened here at some point?
If you can't use const because you're modifying operands, you're badly misusing operator overloading.
If you can't use const because the implementation calls non-const functions, you really should clean those up, or at least provide const alternatives.
If you're calling into code you can't change which doesn't use const, I'd use the const anyway, use const_cast at the deepest available point, and comment it.
As Shmoopty pointed out, the operator is a lot less useful than it should be since it can't be used on const objects, even if only one of them is const. A numeric equality operator that wouldn't support "a == 5" would violate the Law of Least Astonishment in a big way.