Quantcast
Channel: What are the basic rules and idioms for operator overloading? - Stack Overflow
Viewing all articles
Browse latest Browse all 11

Answer by Jan Schultke for What are the basic rules and idioms for operator overloading?

$
0
0

Summary of Canonical Function Signatures

Many operator overloads can return pretty much anything. For example, nothing stops you from returning void in operator==.However, only a few of these signatures are canonical, which means that you would normally write them that way, and that such an operator can be explicitly defaulted with = default.

Assignment Operators

struct X {  X& operator=(const X&) = default;     // copy assignment operator  X& operator=(X&&) noexcept = default; // move assignment operator};

Explicit defaulting with = default; is possible, but you can also implement assignment manually.Move assignment is almost always noexcept, although it isn't mandatory.

Comparison Operators

#include <compare> // for comparison categoriesstruct X {  friend auto operator<=>(const X&, const X&) = default; // defaulted three-way comparison  friend std::strong_ordering<=>(const X&, const X&);    // manual three-way comparison  friend bool operator==(const X&, const X&) = default;  // equality comparisons  friend bool operator!=(const X&, const X&) = default;  // defaultable since C++20  friend bool operator<(const X&, const X&) = default;   // relational comparisons  friend bool operator>(const X&, const X&) = default;   // defaultable since C++20  friend bool operator<=(const X&, const X&) = default;  friend bool operator>=(const X&, const X&) = default;};

See this answer for more information on when and how to default/implement comparisons.

Arithmetic Operators

struct X {  friend X operator+(const X&, const X&); // binary plus  friend X operator*(const X&, const X&); // binary multiplication  friend X operator-(const X&, const X&); // binary minus  friend X operator/(const X&, const X&); // binary division  friend X operator%(const X&, const X&); // binary remainder  X operator+() const;                    // unary plus  X operator-() const;                    // unary minus  X& operator++();                        // prefix increment  X& operator--();                        // prefix decrement  X  operator++(int);                     // postfix increment  X  operator--(int);                     // postfix decrement  X& operator+=(const X&);                // compound arithmetic assignment  X& operator-=(const X&);  X& operator*(const X&);  X& operator/=(const X&);  X& operator%=(const X&);};

It is also possible to take the left operator of binary operators by value, but this is not recommended because it makes the signature asymmetric and inhibits compiler optimizations.

Bitwise Operators

struct X {  using difference_type = /* some integer type */;  friend X operator&(const X&, const X&);         // bitwise AND  friend X operator|(const X&, const X&);         // bitwise OR  friend X operator^(const X&, const X&);         // bitwise XOR  friend X operator<<(const X&, difference_type); // bitwise left-shift  friend X operator>>(const X&, difference_type); // bitwise right-shift  X operator~() const;                            // bitwise NOT  X& operator&=(const X&);                        // compound bitwise assignment  X& operator|=(const X&);  X& operator^(const X&);  X& operator/=(const X&);  X& operator%=(const X&);};

Stream Insertion and Extraction

#include <ostream> // std::ostream#include <istream> // std::istreamstruct X {  friend std::ostream& operator<<(std::ostream&, const X&); // stream insertion  friend std::istream& operator>>(std::istream&, X&);       // stream extraction};

Function Call Operator

struct X {  using result = /* ... */;         result operator()(user-defined-args...) /* const / volatile / & / && */;  static result operator()(user-defined-args...);           // since C++23};

Subscript Operator

struct X {  using key_type = /* ... */;  using value_type = /* ... */;  const value_type& operator[](key_type) const;        value_type& operator[](key_type);  static value_type& operator[](key_type); // since C++23};

Note that operator[] can accept multiple parameters since C++23.

Member Access Operators

struct X {  using value_type = /* ... */;  const value_type& operator*() const; // indirection operator        value_type& operator*();  const value_type* operator->() const; // arrow operator        value_type* operator->();};

Pointer-to-Member Operator

struct X {  using member_type = /* ... */;  using member_pointer_type = /* ... */;  const member_type& operator->*(member_pointer_type) const;        member_type& operator->*(member_pointer_type);};

Address-of Operator

struct X {  using address_type = /* ... */;  address_type operator&() const; // address-of operator};

Logical Operators

struct X {  friend X operator&&(const X&, const X&); // logical AND  friend X operator||(const X&, const X&); // logical OR  friend X operator!(const X&);            // logical NOT};

Note that these don't return bool because they only make sense if X is already a logical type that similar to bool.

User-defined Conversions

struct X {  using type = /* ... */;  operator type() const;          // arbitrary implicit conversion  explicit operator bool() const; // explicit/contextual conversion to bool  template <typename T>    requires /* ... */            // optionally constrained  explicit operator T() const;    // conversion function template};

Coroutine Await

struct X {  using awaiter = /* ... */;  awaiter operator co_await() const;};

Comma Operator

struct X {  using pair_type = /* ... */;  // often a template to support combination of arbitrary types  friend pair_type operator,(const X&, const X&);};

Allocation Functions

struct X {  // class-specific allocation functions  void* operator new(std::size_t);  void* operator new[](std::size_t);  void* operator new(std::size_t, std::align_val_t); // C++17  void* operator new[](std::size_t, std::align_val_t); // C++17  // class-specific placement allocation functions  void* operator new(std::size_t, user-defined-args...);  void* operator new[](std::size_t, user-defined-args...);  void* operator new(std::size_t, std::align_val_t, user-defined-args...); // C++17  void* operator new[](std::size_t, std::align_val_t, user-defined-args...); // C++17  // class-specific usual deallocation functions  void operator delete(void*);  void operator delete[](void*);  void operator delete(void*, std::align_val_t); // C++17  void operator delete[](void*, std::align_val_t); // C++17  void operator delete(void*, std::size_t);  void operator delete[](void*, std::size_t);  void operator delete(void*, std::size_t, std::align_val_t); // C++17  void operator delete[](void*, std::size_t, std::align_val_t); // C++17  // class-specific placement deallocation functions  void operator delete(void*, user-defined-args...);  void operator delete(void*, user-defined-args...);  // class-specific usual destroying deallocation functions  void operator delete(X*, std::destroying_delete_t); // C++20  void operator delete(X*, std::destroying_delete_t, std::align_val_t); // C++20  void operator delete(X*, std::destroying_delete_t, std::size_t); // C++20  void operator delete(X*, std::destroying_delete_t, std::size_t, std::align_val_t); // C++20};// non-class specific replaceable allocation functions ...void* operator new(std::size_t);void* operator delete(void*);// ...

Viewing all articles
Browse latest Browse all 11

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>