Reputation: 133
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
}
Upvotes: 13
Views: 4278
Reputation: 39444
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.
Upvotes: 0
Reputation: 82535
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.
Upvotes: 0
Reputation: 26652
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.
Upvotes: -1
Reputation: 279215
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.
Upvotes: 18
Reputation: 76640
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
.
Upvotes: 4
Reputation: 146910
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.
Upvotes: 7
Reputation: 933
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'.
Upvotes: 9
Reputation: 49008
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.
Upvotes: 0