In a void-returning function, why would you return a void expression instead of omitting the return statement?
Asked Answered
C

8

13

Consider the following snippet:

void Foo()
{
  // ...
}

void Bar()
{
  return Foo();
}

What is a legitimate reason to use the above in C++ as opposed to the more common approach:

void Foo()
{
  // ...
}

void Bar()
{
  Foo();

  // no more expressions -- i.e., implicit return here
}
Chervil answered 8/8, 2010 at 15:15 Comment(0)
H
18

Probably no use in your example, but there are some situations where it's difficult to deal with void in template code, and I expect this rule helps with that sometimes. Very contrived example:

#include <iostream>

template <typename T>
T retval() {
    return T();
}

template <>
void retval() {
    return;
}

template <>
int retval() {
    return 23;
}

template <typename T>
T do_something() {
    std::cout << "doing something\n";
}

template <typename T>
T do_something_and_return() {
    do_something<T>();
    return retval<T>();
}

int main() {
    std::cout << do_something_and_return<int>() << "\n";
    std::cout << do_something_and_return<void*>() << "\n";
    do_something_and_return<void>();
}

Note that only main has to cope with the fact that in the void case there's nothing to return from retval . The intermediate function do_something_and_return is generic.

Of course this only gets you so far - if do_something_and_return wanted, in the normal case, to store retval in a variable and do something with it before returning, then you'd still be in trouble - you'd have to specialize (or overload) do_something_and_return for void.

Harbour answered 8/8, 2010 at 15:29 Comment(1)
Thanks. All the answers were good, but this one illustrated the point nicely.Chervil
P
9

This is a rather useless construction that serves no purpose, unless it is used with templates. That is, if you have defined template functions that returns a value that may be 'void'.

Personable answered 8/8, 2010 at 15:26 Comment(3)
then it's hardly "useless", is it? ;)Centrist
@jalf: Well, in the form it is shown in the question it is pretty useless, isn't it? ;-)Introject
true enough. I interpreted the code in the question as an example of the language feature, and asking when the language feature in general is useful. But fair point. ;)Centrist
Z
7

You would use it in generic code, where the return value of Foo() is unknown or subject to change. Consider:

template<typename Foo, typename T> T Bar(Foo f) {
    return f();
}

In this case, Bar is valid for void, but is also valid should the return type change. However, if it merely called f, then this code would break if T was non-void. Using the return f(); syntax guarantees preservation of the return value of Foo() if one exists, AND allows for void().

In addition, explicitly returning is a good habit to get into.

Zingaro answered 8/8, 2010 at 15:31 Comment(0)
D
4

Templates:

template <typename T, typename R>
R some_kind_of_wrapper(R (*func)(T), T t)
{
   /* Do something interesting to t */
   return func(t);
}

int func1(int i) { /* ... */ return i; }

void func2(const std::string& str) { /* ... */ }

int main()
{
   int i = some_kind_of_wrapper(&func1, 42);

   some_kind_of_wrapper(&func2, "Hello, World!");

   return 0;
}

Without being able to return void, the return func(t) in the template would not work when it was asked to wrap func2.

Distal answered 8/8, 2010 at 15:32 Comment(0)
B
0

The only reason I can think of is if you had a long list of return Foo(); statements in a switch and wanted to make it more compact.

Brobdingnagian answered 8/8, 2010 at 15:21 Comment(0)
A
0

Could be a case where Foo() originally returned a value, but was later changed to void, and the person who updated it just didn't think very clearly.

Araucania answered 8/8, 2010 at 17:23 Comment(0)
P
0

First and foremost, returning void can be helpful when writing templates. You typically don't do it if you know that a function returns void, but it's helpful that it's legal:

template <typename T, typename F>
auto apply(T x, F f) {
    // if f returns void, the return type of apply is deduced to void, and the following
    // return statement is legal
    return f(x);
}

This example may be a bit artificial, but in practice, returning void simplifies the implementation of std::apply.

Another use case is making switch statements more compact:

void one(), two(), three();

void before(int x) {
    switch (x) {
    case 1:
        one();
        break;
    case 2:
        one();
        break;
    case 3:
        one();
        break;
    }
}

void after(int x) {
    switch (x) {
    case 1: return one();
    case 2: return two();
    case 3: return three();
    }
}

Technically, before could also have just one line per case, but putting multiple statements on a single line often conflicts with style guides and/or auto-formatters.

Pursley answered 13/1 at 22:19 Comment(0)
C
-1

The reason is returning memory like math.h always returns. math.h has no void and no empty arguments. There are many practical situations where you need memory.

Consuetudinary answered 8/8, 2010 at 16:23 Comment(1)
What? The math functions take arguments and return values because that's what they need to do to be math functions...Statuette

© 2022 - 2024 — McMap. All rights reserved.