C++ operator overloading, understanding the Google style guide - c++

I am following a book to learn C++ (come from a python background). I've written this, which works:
class CatalogueItem
{
public:
CatalogueItem();
CatalogueItem(int item_code, const string &name, const string &description);
~CatalogueItem() {};
bool operator< (const CatalogueItem &other) const;
...
private:
...
};
...
list<CatalogueItem> my_list;
// this is just me playing around
CatalogueItem items[2];
items[0] = CatalogueItem(4, string("box"), string("it's a box"));
items[1] = CatalogueItem(3, string("cat"), string("it's a cat"));
my_list.push_back(items[0]);
my_list.push_back(items[1]);
my_list.sort();
The part I'm trying out is using the operator < to allow the list to sort itsself.
This all seems good, but http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Operator_Overloading seems to suggest avoiding doing this, which is exactly what the book says to do! ("In particular, do not overload operator== or operator< just so that your class can be used as a key in an STL container; instead, you should create equality and comparison functor types when declaring the container.")
I understand "create equality and comparison functor types" to mean creating comparison functions, like the below one:
bool my_comparison_function(const CatalogueItem &a, const CatalogueItem &b)
{
// my comparison code here
}
Is that what the style guide is referring to?
Does anyone have an option as to which method is more "correct"?
J

A functor type would be more like this:
struct CatalogueItemLessThan
{
bool operator()(const CatalogueItem &a, const CatalogueItem &b)
{
}
};
Then the usage would look like this:
list<CatalogueItem> my_list;
// this is just me playing around
CatalogueItem items[2];
items[0] = CatalogueItem(4, string("box"), string("it's a box"));
items[1] = CatalogueItem(3, string("cat"), string("it's a cat"));
my_list.push_back(items[0]);
my_list.push_back(items[1]);
my_list.sort(CatalogueItemLessThan());
The main advantage of this, is that is allows you to decouple sorting from the object itself. You can now provide as many types of sorting as you want, and use them in different places. (For example, string can be sorted in lexical order, or case-insensitively, or "naturally".
The advantage of using a functor as opposed to a loose function is that you can pass parameters into the comparison to modify how the functor should behave.
In general, the Google style-guide is not really the best style guide out there (IMHO especially their taking exception to exceptions, but that's another discussion). If an object has an obvious sorting order, I often add in a default operator<. If later, there are extra sort orders I want to add, then I add in loose functions. If at a later time, I need to add parameters to the sort order, then I make them into functors. There's no sense in adding in complexity before it's needed.

What Google is trying to say to you is the following.
As you know, you can overload one and only one operator '<' for a given type. Let's say it works for you. But imagine that in the future you might need to sort objects of the same type in accordance with some other comparison criterion. How are you going to do that? The only available version of '<' is already taken.
Of course, you can do that by writing a new named comparison function/functor (not the '<' operator) and explicitly supplying it to the sorting algorithm. You can write 2, 5, 10 more of them. You can write as many as you want. It will work. However, at that point there will be an obvious asymmetry in your code. One comparison function is implemented as 'operator <'. The others - as different named functions/functors. Is there a good reason for this asymmetry?
Well, there might be. If you have a very well-defined and obvious natural sorting method that applies to your type, it makes a very good sense to implement it as operator '<'. This would be the main comparison method. And other, auxiliary, less "natural" comparison methods can and should be implemented as named functions. This is prefectly fine.
However, what if you don't have such an obvious candidate for the "natural" comparison? In this case favoring one method over the other and "wasting" the '<' operator on an arbitrarily chosen one is not a good idea. In this case it is recommended to leave the '<' alone, and stick to named functions/functors instead.
In other words, by overloading the '<' you create a "favorite" comparison for the given type. If that's what you really want - go ahead and do it. But keep in mind that in many cases creating an artificial and arbitrary "favorite" is not a good idea. Don't rush the process of choosing that favorite. Don't take the '<' too early.

A functor type is a C++ type (class or struct), that overloads the () operator so that instances of the type behave like a function. This is similar to a class implementing __call__() in Python.
Some STL collection types like std::map require a key_compare functor to order the keys in interal tree structures and thus providing fast access times. By default, this is std::less, which uses operator< to compare values. Therefore this operator is often provided to allow custom classes to act as keys in std::map (and similar).
Google obviously discourages this in favor of supplying your own comparison functor. So, instead of implementing operator<, you could do the following:
struct my_compare
{
bool operator ()(const CatalogueItem& lhs, const CatalogueItem& rhs)
{
...
}
};
If you must access private members to implement this, declare the functor as a friend of your class.

Related

What a struct/class has to implement to work with many (if not all) STL features when it's inside a container?

For example, if I have a struct to hold some information like this:
struct Two {
int a, b;
}
I don't want to use a tuple and I can't use C++20 and <=> (the highest I can go is C++17).
Then what is the minimum set of operand overloads (and other functions) I have to implement to make it work with all (or most of the) STL algorithms and containers?
If I will assume the user will not do any operation on his own, like these:
Two a(1,2);
Two b(2,3);
const float c = 1.4;
a *= b;
a *= 2;
a += c;
And I do not want to provide anything extra implementation for the user's convenience, only to support the STL.
Is there a documentation page similar to https://www.cplusplus.com/reference/stl/ summarizing them in one document and what they need to have implemented to function?
Note: Yes for this example using a Tuple<int, int> would be more suiting
I disagree. Tuple lacks the ability to give a name for the type and for the members. That is a significant drawback in most cases.
Let's give it default and initializing constructors:
Two(void): a(0), b(0) {
}
Two(int x, int y): a(x), b(y) {
}
I recommend against this in most cases. Aggregate classes are useful.
have to implement my hashFunction. If I understand it correctly that applies to set, map and unordered_map.
No, you don't need a hash function for set nor map. You only need a hash function for unordered containers. For set and map, the keys must be orderable instead.
If I then use this unordered_set, but want to order it:
std::unordered_set<Two, hashFunction> exist;
std::sort(exist.begin(), exist.end());
This isn't possible. You cannot sort unordered containers (the clue is in the name). The iterators of the set are const.
Then I have to implement the - operator so it can compare the diff to know if it's bigger/smaller.
Subtraction operator isn't necessary to sort objects. What you need is a way to compare them. This can be done with a less-than operator, but it isn't necessary since you may use a comparison functor instead (just like you used a hash functor in your example).
If I want to use .find on this set:
auto it = exist.find(Two(i, index)
Then I have to implement the == operator:
Equality comparison is a general requirement of the unordered containers whether you want to use find or not. The equality operator isn't required if you use an equality comparator functor instead.
then how I could know what to implement in the advance?
You don't need to know, because the standard containers and algorithms support custom functors for all such functionality. The user of the class can implement those in any way they prefer.
But you can implement all the operators expected from regular types for convenience of the user of the class. I recommend adding all relational operators like this (C++20 required):
struct Two {
int a, b;
friend auto operator<=>(const Two&, const Two&) = default;
};
In general, you can know what standard library containers and algorithms require by reading their documentation.
if we are using at max C++17 ?
Then you must implement each comparison operator explicitly. Only less-than and equality are used by standard library containers, but it's convenient to have all. You can reduce boilerplate by using a base class such as those from Boost.Operators library.

comparator for sorting a vector contatining pointers to objects of custom class

By this question I am also trying to understand fundamentals of C++, as I am very new to C++. There are many good answers to problem of sorting a vector/list of custom classes, like this. In all of the examples the signature of comparator functions passed to sort are like this:
(const ClassType& obj1, const ClassType& obj2)
Is this signature mandatory for comparator functions? Or we can give some thing like this also:
(ClassType obj1, ClassType obj2)
Assuming I will modify the body of comparator accordingly.
If the first signature is mandatory, then why?
I want to understand reasons behind using const and reference'&'.
What I can think is const is because you don't want the comparator function to be able to modify the element. And reference is so that no multiple copies are created.
How should my signature be if I want to sort a vector which contains pointers to objects of custom class? Like (1) or (2) (see below) or both will work?
vertor to be sorted is of type vector
(1)
(const ClassType*& ptr1, const ClassType*& ptr2)
(2)
(ClassType* ptr1, ClassType* ptr2)
I recommend looking through This Documentation.
It explains that the signature of the compare function must be equivalent to:
bool cmp(const Type1& a, const Type2& b);
Being more precise it then goes on to explain that each parameter needs to be a type that is implicitly convertable from an object that is obtained by dereferencing an iterator to the sort function.
So if your iterator is std::vector<ClassType*>::iterator then your arguments need to be implicitly convertable to ClassType*.
If you are using something relatively small like an int or a pointer then I would accept them by value:
bool cmp(const ClassType* ptr1, const ClassType* ptr2) // this is more efficient
NOTE: I made them pointers to const because a sort function should not modify the values it is sorting.
(ClassType obj1, ClassType obj2)
In most situations this signature will also work, for comparators. The reason it is not used is because you have to realize that this is passing the objects by value, which requires the objects to be copied.
This will be a complete waste. The comparator function does not need to have its own copies of its parameters. All it needs are references to two objects it needs to compare, that's it. Additionally, a comparator function does not need to modify the objects it is comparing. It should not do that. Hence, explicitly using a const reference forces the compiler to issue a compilation error, if the comparator function is coded, in error, to modify the object.
And one situation where this will definitely not work is for classes that have deleted copy constructors. Instances of those classes cannot be copied, at all. You can still emplace them into the containers, but they cannot be copied. But they still can be compared.
const is so you know not to change the values while you're comparing them. Reference is because you don't want to make a copy of the value while you're trying to compare them -- they may not even be copyable.
It should look like your first example -- it's always a reference to the const type of the elements of the vector.
If you have vector, it's always:
T const & left, T const & right
So, if T is a pointer, then the signature for the comparison includes the comparison.
There's nothing really special about the STL. I use it for two main reasons, as a slightly more convenient array (std::vector) and because a balanced binary search tree is a hassle to implement. STL has a standard signature for comparators, so all the algorithms are written to operate on the '<' operation (so they test for equality with if(!( a < b || b < a)) ). They could just as easily have chosen the '>' operation or the C qsort() convention, and you can write your own templated sort routines to do that if you want. However it's easier to use C++ if everything uses the same conventions.
The comparators take const references because a comparator shouldn't modify what it is comparing, and because references are more efficient for objects than passing by value. If you just want to sort integers (rarely you need to sort just raw integers in a real program, though it's often done as an exercise) you can quite possibly write your own sort that passes by value and is a tiny bit faster than the STL sort as a consequence.
You can define the comparator with the following signature:
bool com(ClassType* const & lhs, ClassType* const & rhs);
Note the difference from your first option. (What is needed is a const reference to a ClassType* instead of a reference to a const ClassType*)
The second option should also be good.

Write an oveloaded comparison (==) between two primative types, in C++

As pointed out by this article, it is impossible to overload the comparison operator (==) such that both sides could take primitive types.
"No, the C++ language requires that your operator overloads take at least one operand of a "class type" or enumeration type. The C++ language will not let you define an operator all of whose operands / parameters are of primitive types." (parashift)
I was wondering:
**If I really-really needed to compare two primitives in a non-standard way using the ==, is there a way to implicitly cast them to some other class?
For example, the following code will work for const char* comparison, but it requires an explicit cast. I would prefer to avoid explicit casts if possible.
// With an explicit cast
if(string("a")=="A") // True
// Without the cast
if("a"=="A") // False
// An example overloaded function:
bool operator == (string a, const char* b)
{
// Compares ignoring case
}
Casting can be pretty clunky in some situations, especially if you need to do several casts inside a long expression. So that's why I was looking for a way to automatically cast the first input (or both) to a sting type.
Edit 1:
Another way to do this is to write an isEqual(const char* a, const char* b) function, but I want to avoid this because it will result in a mess of parenthesis if I were to use it inside of a large if-statement. Here's an oversimplified example that still shows what I mean:
if (str1 == str2 || str1 == str3 || str2==str4)
As opposed to:
if (isEqual(str1,str2) || isEqual(str1,str3) || isEqual(str2,str4))
Edit 2:
I know there exist many ways to achieve the desired functionality without overloading the ==. But I looking specifically for a way to make the == work because I then could apply the knowledge to other operators as well.
This question is in fact closely related to the Wacky Math Calculator question I asked a few weeks ago, and being able to overload the == will help make the code look considerably nicer (visually, but perhaps not in a "clean code" way).
And that's I wanted to ask this question here on SO, in case someone had a cool C++ trick up their sleeve that I didn't know about. But if the answer is No then that's fine too.
You could certainly write one or more free functions to do your comparison. It doesn't have to be an operator overload.
for example:
bool IsEqual(const char* a, const string& b)
{
// code
}
bool IsEqual(const string& a, const char* b)
{
// code
}
and so on.
If the types of the operands are given, and you cannot add an overload for equality, because
It is simply not overloadable, because all are primitive types
There is already an overload, which does not do what you want
You do not want to risk violation of the ODR because someone else could be pulling the same kind of stunts you do (In which case a TU-local override might work, aka free file-local. Be aware of adverse effects on templates.)
there are just two options:
Use a wrapper and overload all the operators to your hearts content.
Use a function having the desired behavior explicitly and just forget about the syntax-sugar.
BTW: That standard-library containers and algorithms often can be customized three ways:
Using a type having overloaded operators
Having the used standard traits-class specialized
Providing a different traits-class.
No, there's no way to implicitly cast the primitive types the way you want.
The only way to achieve the desired functionality is either by explicitly casting the inputs into another class as stated in the question, or by creating a free function as shown by #Logicat.

C++ Comparing Vectors

I have a class Table which has a member function std::vector<Attribute> attributeVec(); where Attribute is a seperate class.
I am working with code that would like to do something of the form
if (tableA.attributeVec() == tableB.attributeVec()){ ...
Where tableA and tableB are Table objects.
I'm getting a lot of weird compiler errors in Visual Studio 2012 that say things like
binary '==' : no operator found which takes a left-hand operand of type 'const DatabaseAPI::Attribute' (or there is no acceptable conversion)
So I believe the vectors cannot be compared like that. It would make my life easier if I could get this code to compile, but how could I do that? Can I define the operator? Do I need to rewrite some of the Attribute class so they can be compared?
Specifics: After writing an API, I was given a set of tests which, if reasonable, need to work. While I believe this at least makes unreasonable assumptions about my code (given my API), it wouldn't hurt to implement this in my code.
Thanks!
Vectors can be compared using ==, but their contained type (Attribute in this case) must have a comparison operator==. If you give that to the Attribute class, the comparison should work.
On an unrelated note, that his method
std::vector<Attribute> attributeVec();
is returning a copy of a vector. You have to think whether this is the behaviour you really want.
You need operator== implemented in your Attribute class:
class Attribute {
bool operator== (const Attribute& other) const {
// return true if *this == other, otherwise return false
}
}
BTW: As juanchopanza noticed, it is possible that you could return just a reference to the vector from your attributeVec() function, instead of a copy of it:
std::vector<Attribute>& attributeVec();
That would be more efficient and the comparison (using the operator==) in an expression:
o1.attributeVec() == o2.attributeVec()
still work OK.
The error is basically self explanatory, you need operator== on Attribute.
Take a look at std::equal; the second form allows you to specify your own comparison function.
Example:
bool compareAttributes (const Attribute &a, const Attribute &b) { /* ... */ }
// assumes attributeVec() returns a reference; if not, then remove '&'
const std::vector<Attribute>& attribsA = tableA.attributeVec();
const std::vector<Attribute>& attribsB = tableB.attributeVec();
if(attribsA.size()==attribsB.size() &&
std::equal(attribsA.begin(), attribsA.end(),
attribsB.begin(), compareAttributes))
{ /* ... */ }
Ideally, attributeVec() returns a reference to attribute vectors. If you cannot write it this way, then attribsA and attribsB should not be defined as references. (In this case, you might consider writing a comparison function for Table that does not require generating vectors of Attribute.)

Combined Operator Overloading in C++?

Is it possible to overload operators in such a way that you can capture a specific combination of them? For example lets say I have a custom object myObject of type MyType where [] is already overloaded to pass such calls down to a map object. That said, in the case of the following code:
int value = myObject["someProp"];
I'm already overloading [] but in this case I'd like to know when [] is being called on the object in an assignment, with a reference to the type of object that the property lookup is to be assigned to. This way I can cast the value coming out of the dynamic property lookup and so on and so forth. Any input is appreciated!
For more insight into exactly what I'm trying to accomplish, see this related question of mine.
No, you can't overload on the return type, or on the context in which the call appears (e.g. in an assignment etc).
You could, however, return a proxy object that would have a bunch of overloaded conversion operators. Without seeing what you intend to do, it's hard to say how far you might be able to get with this approach, or whether it's even a sane thing to do.
If you want type deduction for things like this, your best bet is to overload operator() instead, and pass in the thing you're going to be assigning to as a dummy parameter, i.e.:
MyType myObject;
int value = myObject("someProp", value);
I've made something like this work pretty well in the past. In particular, see e.g.:
https://github.com/sgolodetz/hesperus2/blob/master/source/engine/core/hesp/objects/base/ObjectManager.tpp
In principle, it's rather straightforward to do: all that is needed is
for your operator to return a proxy which then overloads the operators
you want to catch. In practice, it can cause more than a few problems;
readers will expect (a op1 b) op2 c to have
the same semantics as T tmp(a ip1 b); tmp op2
c. There are some common exceptions, however:
The operator[] in a multi-dimensional array will often return a
proxy which defines an operator[] itself, in order to support [][]
correctly.
More generally, a container which for whatever reasons needs to know
when a value is modified will have an operator[] which returns a
proxy; within the proxy, assignment is defined as setting the value in
the owning container, and there will be a convertion operator to the
value type, for use in rvalue contexts. Of course, this means that
things like m[i][j].funct() don't work; typically, however, this sort
of thing is used for matrices of numeric types, where member functions
aren't that relevant.
In contexts where it is desirable to support overload resolution based
on the target type (your example), the function can return a proxy with
overloaded conversion operators. You want to be extremely careful with
this—overloaded conversion operators are often a recipe for
overload resolution ambiguities&rdash;but there are enough exceptions
that this situation bears mentionning. (Important, here, is that the
results of the operator will amost always be used to intialize or to
assign to a specific object, the type of which determines which
conversion operator will be called.)
BTW: I might mention that in the example you give, there is no
assignment; it is a classical initialization. In this case, defining
the operator[] to return a proxy which defines operator int() const
would do the trick very well. Before going this route, however, you
should very definitely consider all of the use cases of your class, and
ensure that there are none in which the actual target type is ambiguous.
The other answers are basically correct that you can't do it. aix hints at a solution of a custom return type with overloaded conversion operators, but rightly indicates it isn't a sane thing to do. I've ventured down this path quite often and ultimately implicit conversions, and sequences of conversions, and ambiguities will bite you in you in the behind.
I've had a need of this quite often though. Ultimately I end up going for a series of overloaded functions, or templates, depending on your needs, perhaps like this:
void lookup( int& v, char const * name );
void lookup( double& c, char const * name );
In the template case I created global converters and did the below member function:
template<T>
void lookup( T&v, char const* name ) { v = convert<T>( get(name) ); }
If you want to keep the return value as the lookup you'll have to explicitly call a templated function.
template<T> T get( char const * name ) { ... }
//use
int a = obj.get<int>( "name" );
double b = obj.get<double>( "floaty" );
No, you can't do that.
Moreso, madness that way lies!