85

All C++ operators that I have worked with return something, for example the + operator returns the result of the addition.

Do all C++ operators return something, or are there some C++ operators that do not return anything?

user8240761
  • 975
  • 1
  • 10
  • 15
  • 7
    That depends on how narrowly you define the term "operator". – molbdnilo Jun 30 '20 at 12:47
  • 12
    This is not forced by the standard - for example you can implement ```+=``` to return ```void```, but this is not recommended. Also function call operators can return ```void``` and this is valid – Mircea Ispas Jun 30 '20 at 12:47
  • Hmm. I have a hunch that scope resolution operator `::` doesn't return anything, but I'd have to consult standard to make sure. – Yksisarvinen Jun 30 '20 at 12:47
  • 2
    Is the context of the question for C++ provided types only, or does it also include user-defined types? – Eljay Jun 30 '20 at 13:04
  • @Eljay Only the C++ provided types. – user8240761 Jun 30 '20 at 13:06
  • @user8240761 That's still broad. I assume you mean the basic types (bool, char, int etc) but do you also include the types being defined in the standard library? (ie std::vector, std::list etc). – Martin York Jul 01 '20 at 23:53
  • @Martin York No, I am asking only about the basic types. – user8240761 Jul 02 '20 at 06:11

12 Answers12

119

No, not all operators return something.

Although they are probably not exactly what you are thinking about, note that the delete and delete[] C++ 'keywords' are actually operators; and they are defined as having the void return type - which means they evaluate to nothing (which is not 'something').

From cppreference:

void operator delete  ( void* ptr ) noexcept;
void operator delete[]( void* ptr ) noexcept;
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • 14
    I like your answer, it made me think of the question differently. `delete`, `delete[]`, `throw`, `(void)x;` cast, left side of `,` operator, right side of `,` operator that yields a `void`, a `?:` ternary that uses a `throw` for one of the arms, dfri's `operator void()` (which would be user defined), 眠りネロク's `void operator()()` (which would be user defined). – Eljay Jun 30 '20 at 13:14
  • 10
    It's also confusing that the `delete` operator destroys the object and then calls `operator delete`. Ergo, the `delete` operator and `operator delete` are separate things :( https://stackoverflow.com/a/8918942/845092 – Mooing Duck Jul 01 '20 at 22:18
  • 7
    Not sure why you cite the delete-functions when talking about the delete-operator. But whatever. – Deduplicator Jul 02 '20 at 07:56
  • 4
    @MooingDuck The delete *expression* destroys the object, and then calls `operator delete`. – NathanOliver Jul 02 '20 at 13:17
  • Does the delete count as an operator through, I thought an object is something that acts on an object that is passed?? Delete does not need any object to be passed or created for it to work..... Just like printf..... – Yunfei Chen Jul 10 '20 at 16:31
  • @YunfeiChen Sure, the `delete` and `delete[]` operators *require* something to act on (an *operand*): a pointer to memory allocated by the `new` or `new[]` operator. – Adrian Mole Jul 10 '20 at 18:27
83

Operators of custom types can be overloaded to do the most weirdest things.

for example the + operator returns the result of the addition.

Not necessarily:

#include <iostream>
struct foo {
    int value = 0;
    void operator+(int x) {
        value += x;
    }
};

int main () {
    foo f;
    f + 3;
}

Here operator+ adds the left hand side to the value member, and its return type is void. This is a made-up example, but, in general, not returning something from a custom operator is not unusual.

The only operator that can be overloaded and that has the requirement of returning something, that I am aware of, is operator->. It must either return a raw pointer or an object that has an operator->.

cmaher
  • 5,100
  • 1
  • 22
  • 34
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • Funnily enough, there is actually no constraint on overloaded operators return value. So, operators can return whatever you want. https://en.cppreference.com/w/cpp/language/operators – bracco23 Jul 01 '20 at 09:27
  • 5
    @braccor23 `operator->` is a bit special and needs to return either a pointer or an object which has an `operator->`, not sure if there are other exceptions – 463035818_is_not_an_ai Jul 01 '20 at 09:38
  • 1
    Yes, that's the only constraint. Not even bool for comparison operators. That looks really weird. – bracco23 Jul 01 '20 at 09:41
  • @bracco23 why weird? If you want to do something wrong in C++ then nothing prevents you from doing that, thats not special to operator overloading. There is no reason to disallow "weird" things just because now you don't see that it could be useful. One day someone will need it and then they would be disappointed if it was disallowed only because it is "weird" – 463035818_is_not_an_ai Jul 01 '20 at 09:43
  • @bracco23 consider that `==` Is just a symbol, it has a conventional meaning but with overloading I can define it such that `a == b` means "add `a` and `b` and store the result in `a`". That would be very unconventional, my type wouldnt work with most algorithms and other code, but why not? – 463035818_is_not_an_ai Jul 01 '20 at 09:46
  • @idclev463035818 Unfortunately nothing prevents you from doing something wrong in C++ no matter your intentions ;-). – Peter - Reinstate Monica Jul 01 '20 at 10:00
  • 9
    @idclev463035818: A perhaps more useful example can be Expression Templates. For example, you can make a matrix library where `operator*(Matrix const& left, Matrix const& right)` returns not `Matrix` but instead `MatrixMul`, so that if it is then fed into `operator+(Matrix const& left, MatrixMul const& right)` the operation can be a fused multiply-add which is more efficient than first multiplying then adding. – Matthieu M. Jul 01 '20 at 10:44
  • @MatthieuM. good example. And nice illustration of why it would be bad to resitct things just because now one doesn't see how they could be usefull – 463035818_is_not_an_ai Jul 01 '20 at 10:49
  • @bracco23 Matthieu brought up a good case for why restricting comparisons to return `bool` would be really bad. Also, to make comparisons work with algorithms and other code as expected they just need to return something that can be converted to `bool` – 463035818_is_not_an_ai Jul 01 '20 at 10:51
  • @idclev463035818 I didn't really mean weird in a bad way from the start, is just something that kinda surprises me but at the same time it doesn't?! Like, i'm aware of how useful can be the flexibility of not having the return value constrained, I mean probably with that constraint the change in semantic that operator<< had received in the standard library wouldn't have been possible. – bracco23 Jul 01 '20 at 11:04
  • But also, I think these are all great arguments that could be added to the answer, since they do help in getting a better understanding. – bracco23 Jul 01 '20 at 11:05
  • @bracco23 frankly, I dont think so, becaue the quesiton is not about what is returned, only whether someting or nothing is returned. The thingy about `operator->` is relevant, maybe I'll add that – 463035818_is_not_an_ai Jul 01 '20 at 11:07
  • Of course the `<<` used in this example is itself an operator overload which doesn't return anything. It's so common now in C++ that we often forget it was originally just meant for bitwise left-shift. It's not technically part of the language itself but a feature of the STL. – Darrel Hoffman Jul 01 '20 at 13:58
  • 1
    @DarrelHoffman When `<<` and `>>` are overloaded for I/O operations, they're expected to return the stream so that you can cascade them: `stream << foo << bar;` – Barmar Jul 01 '20 at 14:18
  • I believe the new C++20 `operator co_await` has a similar restriction to `operator->` - it needs to return something with either an `operator co_await` or the three member functions awaiters need. (Although, at least with gcc 10, you can absolutely *define* these two operators to not satisfy their requirements and even invoke them by calling the operator as a member function, as long as you never try to use the operators' usual syntax - I don't know if such programs are legal according to the standard though and even if it is, you'd obviously make people very upset if you wrote such a program) – Milo Brandt Jul 01 '20 at 16:08
  • [boost::spirit::qi](https://www.boost.org/doc/libs/1_66_0/libs/spirit/doc/html/spirit/qi/tutorials/warming_up.html) is also an amazing example of where they've made custom operators with surprising return values to make an _amazing_ tool – Mooing Duck Jul 01 '20 at 17:08
  • It doesn't matter what the operator _does_. What matters is its return type - which in your custom type you've chosen to be `void`. I'd rephrase your answer accordingly. – einpoklum Jul 02 '20 at 15:34
  • @einpolklum not sure if I understood what you mean. I am hestitant to rephrase the answer too much, but I tried to make the example less odd and rephrased a bit. Better? Feel free to suggest an edit – 463035818_is_not_an_ai Jul 02 '20 at 22:07
35

To nitpick, operators don't return anything. They are just lexical elements that we use to create expressions in the language. Now, expressions have types and may evaluate to values, and I assume this is what you mean by operators "returning things".

And, well, yes. There are C++ expressions with type void (and consequentially don't evaluate to any value). Some are obvious, others less so. A nice example would be

throw std::runtime_error()

throw is an expression under the C++ grammar. You can use it in other expressions, for instance in the conditional expression

return goodStatus() ? getValue() : throw std::runtime_error();

And the type of a throw expression, is void. Obviously since this just causes execution to rapidly go elsewhere, the expression has no value.

Paolo
  • 21,270
  • 6
  • 38
  • 69
StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
21

None of the built-in C++ operators return something. Overloaded C++ operators return something insofar that the operator notation is a syntactic sugar for a function call.

Rather, operators all evaluate to something. That something has a well-defined value as well as a type. Even the function call operator void operator()(/*params*/) is a void type.

For example, +'a' is an int type with the value of 'a' encoded on your platform.

If your question is "Can C++ operators have a void return type?" then the answer is most certainly yes.

einpoklum
  • 118,144
  • 57
  • 340
  • 684
Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    "None of the C++ operators return something." I dont understand what you are trying to say. Are you refering to operators for built-in types? – 463035818_is_not_an_ai Jun 30 '20 at 12:50
  • 14
    @idclev463035818: It's the term *return* I have an issue with. The only thing in C++ that returns something is a function. Expressions *evaluate* to something. – Bathsheba Jun 30 '20 at 12:51
  • 7
    operators of class types are methods that return something – 463035818_is_not_an_ai Jun 30 '20 at 12:51
  • @idclev463035818: Indeed, but when used in an expression, one should talk about *evaluating* to something. I'm not being particularly clear, and I think there are better answers. Might tin this. – Bathsheba Jun 30 '20 at 12:52
  • 4
    This is an important point. Sloppy terminology leads to confusion. +1. – Pete Becker Jun 30 '20 at 13:18
  • 1
    @PeteBecker: Unfortunately, the C and C++ Standards have lots of sloppy terminology, which dates to a time when compiler writers were expected to fill in any gaps by seeing what other compilers had been doing before the Standard was written. For example, given the evaluation of `somePointer = &(someStructArray[i++].arrayMember[j];` what term would describe what is done with the glvalue `someStructArray[i++]`? It isn't "evaluated", since evaluation of that sub-expression would invoke UB if the indicated array member held Indeterminate Value, but evaluation of the whole expression would not. – supercat Jun 30 '20 at 21:17
  • 3
    @supercat — your comment maligns a bunch of hardworking people, including me. Those of us who wrote the standard **never** expected compiler writers to fill in details by polling other compilers, present or past. The goal of the standard was and is to clearly define the syntax and semantics of the C++ programming language. Yes, the result isn’t perfect; there are many issues addressed in the latest standard that weren’t addressed in earlier versions. That comes from experience, recognizing complications that simply weren’t seen at the time. – Pete Becker Jul 01 '20 at 02:33
  • 2
    @PeteBecker With all due respect; "None of the C++ operators return something" seems a non sequitur, if the implementation contains a return statement with a value. I was always under the impression that operators are simply syntactic sugar for functions, many of which certainly "return something" in all reasonable uses of that term. Is that not so? (Of course functions also "evaluate to something"; "returning" is the perspective of the callee, "evaluating to" is the perspective of the caller.) I cannot see the important point you see. – Peter - Reinstate Monica Jul 01 '20 at 10:08
  • 1
    @Peter-ReinstateMonica — yes, the statement should have “none of the built-in operators” returns a value. **Overloaded** operators resolve to function calls. Nevertheless, talking about expressions returning values is a misuse of terminology, and leads to confusion. – Pete Becker Jul 01 '20 at 11:03
  • 3
    @Peter-ReinstateMonica — here’s a stronger version. The expression `I++` does not return a value. If the type of `i` is a user-defined type, that expression is implemented as `operator++`, which is a function that returns a value. You call that “syntactic sugar”; I call that a distinction that has important consequences. – Pete Becker Jul 01 '20 at 11:15
13

You can actually define a function call operator to return nothing. For example:

struct Task {
   void operator()() const;
};
JFMR
  • 23,265
  • 4
  • 52
  • 76
11

operator void(): user defined conversion function to void

You may define the peculiar operator void() conversion function, where the compiler will even warn you that the T to void conversion function will never be used:

#include <iostream>

struct Foo {
    operator void() { std::cout << "Foo::operator void()!"; }
    // warning: conversion function converting 'Foo' to 
    //          'void' will never be used
};
    
int main() {
    Foo f;
    (void)f;            // nothing
    f.operator void();  // Foo::operator void()!
}

as governed by [class.conv.fct]/1

[...] A conversion function is never used to convert a (possibly cv-qualified) object to the (possibly cv-qualified) same object type (or a reference to it), to a (possibly cv-qualified) base class of that type (or a reference to it), or to (possibly cv-qualified) void.117

(117) These conversions are considered as standard conversions for the purposes of overload resolution ([over.best.ics], [over.ics.ref]) and therefore initialization ([dcl.init]) and explicit casts. A conversion to void does not invoke any conversion function ([expr.static.cast]). Even though never directly called to perform a conversion, such conversion functions can be declared and can potentially be reached through a call to a virtual conversion function in a base class.

Whilst, however, as is shown above, you can still invoke it using the explicit .operator void() syntax.

dfrib
  • 70,367
  • 12
  • 127
  • 192
5

The operators defined (builtin) by the language are tokens used to perform different kinds of computations:

  • arithmetic (+,-,*,/)
  • increment/decrement (++,--)
  • assignment (=,+=,-=,*=,/=,%=,>>=,<<=,&=,^=,|=)
  • logic (!,&&,||)
  • relational (==,!=,>,<,>=,<=)
  • conditional ?
  • comma

and so on. The list can be very extensive.

In language references like this one or this one, these are not necessarily referenced as returning something, just performing an arithmetic or logic operation, a comparison by which means a variable may be modified, etc.

Since this operation results in some value, it may be interpreted as been "returned" by the operator, but it is different from a function return value.

The overloaded operators, on the other hand, can be defined with a return value of some type, even that can be void, so, no, not all operators return some value in C++.

ram0nvaldez
  • 165
  • 1
  • 2
  • 7
4

I'm assuming you're talking about operator functions and not operators as a syntactic unit of the language.

If you overload operators on any type, you may actually return whatever you want.

This also makes a lot of sense, because operations like * or () may sometimes very intuitively not return their input type. Imagine multiplying a complex number type with a real number type. Or an operator that returns an element from a collection.

You may also overload the ++ and -- operators to not return anything thus removing the extremely error-prone mixing of side-effect and expression value that the standard version has.

Kafein
  • 357
  • 1
  • 7
2

No. Consider these two examples here:

int multiply (int a, int b) {
   return a*b;
}

void multiply_void(int a, int b) {
   cout << a*b;
//or cout << multiply(a,b);
}

First function will return an integer value which can be used by another function. The value is returned and stored in memory to be used when necessary. If not, it is not visible to human & just sits happily in the memory.

Second function will output to the default output device(usually console). The value returned by the multiplication operator is passed to an output device. The function multiply_void does not return an actual value.

Gokhan Dilek
  • 4,314
  • 4
  • 21
  • 24
0

All operators return something. They are called operators because they operate something , therefore they will return something. Those Operators who do not return something cant be called operators. Either they will return some value or return True or False depending upon the situation.

Alby
  • 43
  • 5
0

Operators on their own do not necessarily return anything. Function calls return values. Operators can result in values. Operators can sometimes invoke functions. Examples include:

• The function call operator.

• An overloaded operator that gets transformed into a function call.

• operator new, which is invoked as part of a new-expression, is a function call.

My only purpose in mentioning function calls is to clarify the result vs. return. Based on looking at all 126 instances of “return” and words derived from it in [expr], the section seems to carefully use the word return to refer to:

• the result of a function call

• aspects of control flow related to coroutines

OK, that’s enough pedantry on result vs. return.

Saddam
  • 1,174
  • 7
  • 14
0

C++ Operators return something or not is depends upon how you used them. Built-In C++ operators return some value until and unless enforced to return void.