tags:

views:

266

answers:

8

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
}
A: 

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.

Karl Bielefeldt
A: 

None that I can think of!

Kevin McFarlane
+8  A: 

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'.

Stefan Rådström
then it's hardly "useless", is it? ;)
jalf
@jalf: Well, in the form it is shown in the question it is pretty useless, isn't it? ;-)
Stefan Rådström
@Stefan: 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. ;)
jalf
+12  A: 

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.

Steve Jessop
Thanks. All the answers were good, but this one illustrated the point nicely.
kirk0
+7  A: 

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.

DeadMG
+4  A: 

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.

Tyler McHenry
A: 

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.

LarsOn
What? The math functions take arguments and return values because that's what they need to do to be math functions...
GMan
A: 

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.

Kristopher Johnson