简体   繁体   中英

C++: return the return value of a void function from a void function

I have several void functions (lets call them foo and bar) that share the same void function cleanup that, well, cleans up after them if they mess up:

#include <iostream>

void cleanup() { std::cout << "doing cleanup" << std::endl; }

void foo(int & i) {
    if(i == 0) { return cleanup(); }
    --i;
    if(i == 0) { return cleanup(); }
    ++i;
}

void bar(int & i) {
    if(i == 0) { return cleanup(); }
    ++i;
    if(i == 0) { return cleanup(); }
    --i;
}

int main() {
    int i = 0;
    foo(i);
    bar(i);
    return 0;
}

cpp.sh happily compiles and runs the code.

Thanks to the answer to this question I know that I can return an object of type void. But I don't know if it applies to returning void return values.

What do you think, does the code comply with the standard?

And would you rather return dummy integers to make the code more readable? Or would the useless return values make the code harder to read?

edit: I feel like I need to add some clarification as to why eg 'cleanup(); return;' is not a solution. The actual code is more complex than the example and depending on where I leave the function some other stuff happens after the cleanup() call. 'return cleanup();' is just a convenient way of not putting all the stuff behind it in conditionals in instances where I can/have to leave immediately.

From n4582

6.6.3 The return statement [stmt.return]

Paragraph 2

The expr-or-braced-init-list of a return statement is called its operand. A return statement with no operand shall be used only in a function whose return type is cv void, a constructor (12.1), or a destructor (12.4). A return statement with an operand of type void shall be used only in a function whose return type is cv void. A return statement with any other operand shall be used only in a function whose return type is not cv void; the return statement initializes the object or reference to be returned by copy-initialization (8.5) from the operand.

Questions:

But I don't know if it applies to returning void return values.

Yes its perfectly valid to return a void expression from a function that return void. This becomes very handy in templated code so you don't have to special case void functions.

What do you think, does the code comply with the standard?

Yes absolutely.

And would you rather return dummy integers to make the code more readable? Or would the useless return values make the code harder to read?

That's totally up to you and your aesthetics. Does it make the code look more readable to you (or do you have coding guidelines that you need to follow). Personally I would not return dummy values (as the user may expect some meaning from them).

This is useful for perfect forwarding. Imagine that you have a functor of type (template-parameter), so the return type can potentially be anything. This permission to return a value of type void allows you to call the functor and expose its return value to your caller, without having to write separate code for the case of no return value.

template<typename Functor, typename... Args>
auto forward(Functor what_to_call, Args... args) -> decltype(what_to_call(std::forward<Args>(args)...))
{
    return what_to_call(std::forward<Args>(args)...);
}

That's already pretty messy, but if not for the ability to propagate void return types using the return keyword, you'd need two variations controlled by enable_if .

template<typename Functor, typename... Args>
auto forward(Functor what_to_call, Args... args) -> enable_if<is_same_type<decltype(what_to_call(std::forward<Args>(args)...)), void>::value, void>::type
{
    what_to_call(std::forward<Args>(args)...);
    return;
}

template<typename Functor, typename... Args>
auto forward(Functor what_to_call, Args... args) -> enable_if<!is_same_type<decltype(what_to_call(std::forward<Args>(args)...)), void>::value, decltype(what_to_call(std::forward<Args>(args)...))>::type
{
    return what_to_call(std::forward<Args>(args)...);
}

So, return function_returning_void(); is designed for special circumstances where it is useful. Don't feel that you have to return a dummy object of type void or any other type everywhere just because it is possible. For example, don't do return void(); or return -1; when simply return; will do.

What do you think, does the code comply with the standard?

Yes, it does. In a function returning void , you may use an expression in a return statement if the type of the expression is void . Which it is, if it is a call to a function that also returns void .

And would you rather return dummy integers to make the code more readable? Or would the useless return values make the code harder to read?

I don't think dummy integers would make the code more readable. Programmers expect return values to be meaningful.

What I think would be more readable, is to split the function call and the return to separate statements:

cleanup();
return;

Although I admit, that's entirely a matter of opinion.

If a function would return no value, it would be wiser to check if the function succeeded in doing what it had to do. A Little example:

        bool foo()
        {
        if (DoSomeThing() == true)
        {
            return true;
        }
        else
        {
            return false;
        }

Then you could the return value of foo():

        if (!foo())
        {
            Console.WriteLine("foo returned false!");
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM