If I already have operator > and operator < defined (and operator ==), do I need to define operator >= and operator <=, or will the compiler declare them for me if I intentionally don't declare them?
Also, if I have operator == defined, will the compiler declare operator != for me?
No, the Compiler won't declare/define any of the operators you did not define manually. However, Boost.Operators might be to your liking - it does exactly what you want the compiler to do.
The compiler won't do anything itself for you here, but it's
relatively simple to generate automatically by inheriting from
an appropriate class, something like:
template< typename DerivedType >
class ComparisonOperators
{
public:
friend bool operator!=(
DerivedType const& lhs,
DerivedType const& rhs )
{
return !(lhs == rhs);
}
friend bool operator<=(
DerivedType const& lhs,
DerivedType const& rhs )
{
return !(rhs < lhs);
}
friend bool operator>(
DerivedType const& lhs,
DerivedType const& rhs )
{
return rhs < lhs;
}
friend bool operator>=(
DerivedType const& lhs,
DerivedType const& rhs )
{
return !(lhs < rhs);
}
protected:
~ComparisonOperators() {}
} ;
Define < and == in your class, and derive from this, and
you'll get all of the operators:
class MyClass : public ComparisonOperators<MyClass>
{
// ...
public:
bool operator==( MyClass const& other ) const;
bool operator<( MyClass const& other ) const;
// ...
};
Just a note: I've manually simplified the version I actual use,
which defines == and < as well, looks for the member
functions compare and isEqual, and uses compare for ==
and != when there is no isEqual. I don't think I've
introduced any errors, but you never know.
There are already some good answers here using boost and inheritance. But as someone noted - using inheritance for operator creation seems... wrong.
I know #defines are "taboo" in C++, but still that's what I use here.
I have a #define in my general utility include that goes like this:
#define CREATE_COMPARITORS(name) \
inline bool operator>(const name &o){return o<*this;} \
inline bool operator<=(const name &o){return not (o<*this);} \
inline bool operator>=(const name &o){return not (*this<o);} \
inline bool operator!=(const name &o){return not (*this==o);}
Then if I have a class, all I need to declare is operator< and operator==:
class ttt{
//...
bool operator<(const ttt &o);
bool operator==(const ttt &o);
CREATE_COMPARITORS(ttt);
//...
};
Related
Is this standard behavior in C++20? I couldn't find anything about it in cppreference.
I've just tried both on Clang and on Visual Studio and it works and it doesn't give me any sort of error or warning. I also checked with the debugger to see if operator== was being called and it was! Does C++20 now allows for the automatic generation of operator!= when operator== is present? Does it default to a sane !(a == b)? If that's so, then that's awesome for C++!
!= auto generated from == in C++20?
Is this standard behavior in C++20?
Yes. operator!= is auto generated from operator== in C++20.
Furthermore, all four relational operators are generated if you define operator<=>, and all of the comparison operators are generated if you define operator<=> as defaulted.
What you want to do in most cases:
struct example
{
std::string a;
int b;
auto operator<=>(const example&) const = default;
};
What you can do in older C++ version is to use the CRTP (Curriously Recuring Template principle).
The idea is to have a template base, and the template parameter is the Derived class :
template <typename Derived>
class Comparable {
public:
friend constexpr auto operator!=(const Derived &a, const Derived &b) noexcept { return !(a == b); }
friend constexpr auto operator<=(const Derived &a, const Derived &b) noexcept { return !(b < a); }
friend constexpr auto operator>(const Derived &a, const Derived &b) noexcept { return b < a; }
friend constexpr auto operator>=(const Derived &a, const Derived &b) noexcept { return !(a < b); }
};
And so, you can use it like this :
struct Example : Comparable<Example> {
friend bool operator==(const Example &a, const Example &b);
friend bool operator<(const Example &a, const Example &b);
};
If you declare only the == operator, you will have the != generated automatically, and if you provide both the < and == all operators will be defined :)
I'm writing a class named Double which extends the built in type 'double' in c++. It has a data member of the type 'double'. For the class Double I need to overload many basic arithmetic operators like "+", "-", "*", "/". For example, the "+" operator is overloaded this way:
Relation<Double>* operator+ (Double &d2)
// Relation is a abstract class template.
{
/*
...code that do something else.
*/
return new Plus<Double>(this, &d2); // Plus is derived from Relation.
}
// Double + Double returns a Relation pointer.
and the "-" operator is overloaded fast the same way:
Relation<Double>* operator- (Double &d2)
{
/*
...code that do something else but the same as above.
*/
return new Minus<Double>(this, &d2);
}
The actual calculation is done by the member function in the Relation class. The only difference of the operators' bodies is the object initialized(Plus vs Minus).
For operator that takes exactly two operands, I should alway do the overloading like this, which is duplicated and not nice.
So template function comes to my mind. But the problem is, I can pass Plus or Minus as template argument, but can not pass the operator. How could I make a template or use other methods to do the overloading of these operators?
Yes, operator overloading may be a pain and source of code duplication, see this suggestion to the standard to ease it.
For now the only I can think about is something like this:
template<typename T>
struct OperatorMinus {
static T doIt(T const& lhs, T const& rhs) { return lhs - rhs; };
}
template<typename T>
struct OperatorPlus {
static T doIt(T const& lhs, T const& rhs) { return lhs + rhs; };
}
template<typename T, typename U>
class Operator: public Relation<T>
public:
Operator(T const& lhs, T const& rhs): _lhs(lhs), _rhs(rhs) {}
T doIt() override {
return U::doIt(_lhs, _rhs);
}
private:
T _lhs;
T _rhs;
};
Relation<Double>* operator+ (Double &d2)
{
return new Operator<Double, OperatorPlus<Double>>(this, &d2);
}
the title may be a bit confusing so let me elaborate.
Say, I have a class template<bool is_const> foo that can take one of two forms, const or non-const based on the template parameter. This class has some operators overloaded like
bool foo<is_const>::operator==(const foo<is_const> &other) const {
return this->a == other.a;
}
The actual return value is irrelevant here. The point is I have quite a few of those operators and for none of them does it really matter what the value of is_const is for either of the two operands. So, I would like to avoid having to duplicate each operator (once for is_bool==true and once for is_bool==false). Is it possible to define the function in a way that it doesn't really matter what value is_bool has? Kind of like const foo<> &other (which doesn't work, I tried that).
You can make the operator a template:
template <bool B>
bool operator==(const foo<B> & other) const
{
return a = other.a;
}
As you discovered, it is generally preferable to have operator overloads be non-member functions, possibly friends:
template <bool A, bool B>
friend bool operator==(const foo<A> & lhs, const foo<B> & rhs)
{
return lhs.a == rhs.a;
}
you can have template method:
template<bool is_const>
class foo {
public:
template<bool is_another_const>
bool operator==( const foo<is_another_const> &other ) const;
};
Thanks to both of you, #kerek-sb and #slava. Even though your answers didn't really solve the problem it pushed me in the right direction.
The problem with your solutions is that &other is not necessarily the same class as this any more and thus has no access to private members, which is unfortunately crucial for the comparison operators to work. So I played around with making the function a friend. What I arrived at is this:
template <bool lhs_const, bool rhs_const>
friend bool operator==(const _Iterator<lhs_const>& lhs, const _Iterator<rhs_const>& rhs) {
return (lhs.m_pos == rhs.m_pos) && (lhs.m_buffer == rhs.m_buffer);
}
The friend keyword gives access to private members for both template instantiations. It's not technically a member function any more but that doesn't really matter much.
We are about to migrate (around the next two years) all our compilers to C++11-ready compilers.
Our clients will use our headers, and we are now on the position to write (more or less from scratch) headers for our new API.
So we must choose between keeping to C++03 enums (with all their warts), or use a wrapping class to simulate C++11 notation because we want, in the end, to move those enums to C++11.
Is the "LikeEnum" idiom proposed below a viable solution, or are there unexpected surprises hiding behind it?
template<typename def, typename inner = typename def::type>
class like_enum : public def
{
typedef inner type;
inner val;
public:
like_enum() {}
like_enum(type v) : val(v) {}
operator type () const { return val; }
friend bool operator == (const like_enum & lhs, const like_enum & rhs) { return lhs.val == rhs.val; }
friend bool operator != (const like_enum & lhs, const like_enum & rhs) { return lhs.val != rhs.val; }
friend bool operator < (const like_enum & lhs, const like_enum & rhs) { return lhs.val < rhs.val; }
friend bool operator <= (const like_enum & lhs, const like_enum & rhs) { return lhs.val <= rhs.val; }
friend bool operator > (const like_enum & lhs, const like_enum & rhs) { return lhs.val > rhs.val; }
friend bool operator >= (const like_enum & lhs, const like_enum & rhs) { return lhs.val >= rhs.val; }
};
Which would enable us to upgrade our enums without needing undesirable changes in the user code:
// our code (C++03) | our code C++11
// --------------------------------------+---------------------------
|
struct KlingonType | enum class Klingon
{ | {
enum type | Qapla,
{ | Ghobe,
Qapla, | Highos
Ghobe, | } ;
Highos |
} ; |
} ; |
|
typedef like_enum<KlingonType> Klingon ; |
|
// --------------------------------------+---------------------------
// client code (both C++03 and C++11)
void foo(Klingon e)
{
switch(e)
{
case Klingon::Qapla : /* etc. */ ; break ;
default : /* etc. */ ; break ;
}
}
Note: The LikeEnum was inspired by the Type Safe Enum idiom
Note 2: Source compatibility doesn't cover compilation error because of implicit conversion to int: Those are deemed undesirable, and the client will be notified in advance to make to-integer conversion explicit.
The short answer is yes, that is a viable solution (with one fix).
Here's the long answer. :)
You have a compile-time error with your comparison functions, strictly speaking. This will cause portability issues with standard-compliant compilers. In particular, consider the following:
bool foo(Klingon e) { return e == Klingon::Qapla }
The compiler shouldn't know which overload of operator== to use, as both converting e to KlingonType::type implicitly (via operator type() const) and converting Klingon::Qapla to Klingon implicitly (via Klingon(type)) need one conversion.
Requiring operator type() const to be explicit will fix this error. Of course, explicit doesn't exist in C++03. This means you'll have to do as #Yakk suggests in the comments and use something similar to the safe-bool idiom for inner's type. Removing operator type() const entirely is not an option because it would remove explicit conversions to integral types.
Since you say you're fine with implicit conversions still being possible, a simpler fix would be to also define comparison functions with the underlying enum type. So in addition to:
friend bool operator == (const like_enum & lhs, const like_enum & rhs) { return lhs.val == rhs.val; }
friend bool operator != (const like_enum & lhs, const like_enum & rhs) { return lhs.val != rhs.val; }
friend bool operator < (const like_enum & lhs, const like_enum & rhs) { return lhs.val < rhs.val; }
friend bool operator <= (const like_enum & lhs, const like_enum & rhs) { return lhs.val <= rhs.val; }
friend bool operator > (const like_enum & lhs, const like_enum & rhs) { return lhs.val > rhs.val; }
friend bool operator >= (const like_enum & lhs, const like_enum & rhs) { return lhs.val >= rhs.val; }
you'll also need:
friend bool operator ==(const like_enum& lhs, const type rhs) { return lhs.val == rhs; }
friend bool operator !=(const like_enum& lhs, const type rhs) { return lhs.val != rhs; }
friend bool operator < (const like_enum& lhs, const type rhs) { return lhs.val < rhs; }
friend bool operator <=(const like_enum& lhs, const type rhs) { return lhs.val <= rhs; }
friend bool operator > (const like_enum& lhs, const type rhs) { return lhs.val > rhs; }
friend bool operator >=(const like_enum& lhs, const type rhs) { return lhs.val >= rhs; }
friend bool operator ==(const type lhs, const like_enum& rhs) { return operator==(rhs, lhs); }
friend bool operator !=(const type lhs, const like_enum& rhs) { return operator!=(rhs, lhs); }
friend bool operator < (const type lhs, const like_enum& rhs) { return operator> (rhs, lhs); }
friend bool operator <=(const type lhs, const like_enum& rhs) { return operator>=(rhs, lhs); }
friend bool operator > (const type lhs, const like_enum& rhs) { return operator< (rhs, lhs); }
friend bool operator >=(const type lhs, const like_enum& rhs) { return operator<=(rhs, lhs); }
After fixing the above, there is little noticeable difference semantically (ignoring implicit conversions being possible). The only difference I found is the value of std::is_pod<Klingon>::value from <type_traits> in C++11. Using the C++03 version, this will be false, whereas using enum classes, this will be true. In practice, this means (without optimizations) that a Klingon using enum class can be carried around in a register whereas the like_enum version will need to be on the stack.
Because you don't specify the underlying representation of the enum class, sizeof(Klingon) will probably be the same for both, but I wouldn't rely on it. The unreliability of the underlying representation chosen by different implementations was part of the motivation behind strongly-typed enums after all.
Here's proof of the above two paragraphs for clang++ 3.0+, g++ 4.5+, and msvc 11+.
Now in terms of the compiled output, both obviously will have incompatible ABI. This means your entire codebase needs to use either one or the other. They will not mix. For my system (clang++-3.5 on OSX), the above function's symbol is __Z1f9like_enumI11KlingonTypeNS0_4typeEE for the C++03 version and __Z1f7Klingon for the C++11 version. This should only be an issue if these are exported library functions.
The outputted assembly is identical in my testing for clang++ and g++ after turning optimizations to -O2. Presumably other optimizing compilers will also be able to unwrap Klingon to KlingonType::type. Without optimizations, the enum class version will still of course avoid all the constructor and comparison operator function calls.
I experts, once again while practicing online, i encountered another problem. This is regarding function template. I am able to create the template but i am not sure how to overload appropriate operator. Please advise.
Question
A function template largestOfTree to return the largest of 3 elements of the same parameterised type. To what class can the function template be applied? Write a class trainEngine with fields for name,model,mass. Overload the appropriate operator so the largestOfThree function template can be applied to three trainEngine objects.
So far ?
template<class T>
bool largestOfThree(T t1, T t2, T t3){
if(t1<t2&&t2<t3){
return true;
}else{
return false;
}
}
trainEngine
class trainEngine {
private:
string name;
string model;
string mass;
public:
friend bool operator<(trainEngine const& lhs) {
if (lhs.name<lhs.model&&lhs.model<lhs.mass){
return true;
}
};
A friend operator< is going to be non-member and should thus be binary. Moreover, you forgot the return type. You likely want:
friend bool operator<(trainEngine const& lhs, trainEngine const& rhs) {
// implementation
}
This would go where your operator< declaration is currently.
Here is a list of idiomatic signatures for operator overloads, and a more elaborate explanation of what juanchopanza mentioned in the comments. Note that the non-member operators can be defined within the class body if they are marked as friends. (They are still non-member functions if you do this.)
If you overload operator '<', you should also overload operator '>'
and you have to write return type bool also.
friend bool operator<(trainEngine const& obj1, trainEngine const& obj2)
In fact, it’s convention in most code to prefer the usage of < over > But more generally, always overload the complete set of related operators; in your case, this would probably also be ==, !=, <= and >=.
Let me note that currently your implementation only depends on the right-hand-side (which you call lhs!). It is surely not what you want.
I think you wanted something like this:
bool operator<(trainEngine const& rhs) {
if(name!=rhs.name)
return(name<rhs.name);
if(model!=rhs.model)
return (model<rhs.model);
return (mass<rhs.mass);
}
or the friend version:
//within the class
friend bool operator<(trainEngine const& lhs, trainEngine const& rhs);
//outside the class
bool operator<(trainEngine const& lhs, trainEngine const& rhs) {
if(lhs.name!=rhs.name)
return(lhs.name<rhs.name);
if(lhs.model!=rhs.model)
return (lhs.model<rhs.model);
return (lhs.mass<rhs.mass);
}