【问题标题】:C++: return the return value of a void function from a void functionC++:从 void 函数返回 void 函数的返回值
【发布时间】:2016-08-28 19:50:52
【问题描述】:

我有几个 void 函数(我们称它们为 foo 和 bar),它们共享相同的 void 函数清理,如果它们搞砸了,它们会在它们之后清理:

#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 愉快地编译并运行代码。

感谢the answer to this question 我知道我可以返回 void 类型的对象。但我不知道它是否适用于返回 void 返回值。

你怎么看,代码符合标准吗?

您宁愿返回虚拟整数以使代码更具可读性吗?还是无用的返回值会使代码更难阅读?

编辑:我觉得我需要澄清一些原因,例如'清理();返回;'不是解决方案。实际代码比示例更复杂,并且取决于我将函数留在哪里,在 cleanup() 调用之后会发生一些其他事情。 '返回清理();'这只是一种方便的方法,在我可以/必须立即离开的情况下,不要把所有的东西都放在条件句中。

【问题讨论】:

  • “感谢对这个问题的回答,我知道我可以返回 void 类型的对象。” 没有 void 类型的对象,并且返回类型为void 的函数只返回控制权。
  • 为什么不直接{ cleanup(); return; }?
  • 或者使用 RAII 这样你就不必编写清理代码了。
  • @a.peganz 您可以将其他一些东西放在 RAII 类型中,然后在函数退出时将其销毁并运行代码。这样代码可以自行管理,您不必记住在每个退出点都调用cleaup。
  • @a.peganz RAII 不仅仅是分配和销毁资源。如果您需要运行一些代码,任何代码,并且您希望此代码在函数返回时运行,而不管该函数返回的原因,RAII 都可以用来执行此操作。

标签: c++ coding-style standards-compliance


【解决方案1】:

来自n4582

6.6.3 返回语句[stmt.return]

第 2 段

return 语句的 expr-or-braced-init-list 称为它的操作数。没有操作数的 return 语句只能用于返回类型为 cv void 的函数、构造函数 (12.1) 或析构函数 (12.4)。 带有 void 类型操作数的 return 语句只能在返回类型为 cv void 的函数中使用。 带有任何其他操作数的 return 语句只能在返回类型不是 cv 的函数中使用空白; return 语句初始化要通过复制初始化 (8.5) 从操作数返回的对象或引用。

问题:

但我不知道它是否适用于返回 void 返回值。

是的,从返回 void 的函数返回 void 表达式是完全有效的。这在模板化代码中变得非常方便,因此您不必使用特殊情况的 void 函数。

你怎么看,代码符合标准吗?

绝对是的。

您宁愿返回虚拟整数以使代码更具可读性吗?还是无用的返回值会使代码更难阅读?

这完全取决于您和您的审美。它是否使您的代码看起来更具可读性(或者您是否有需要遵循的编码指南)。就我个人而言,我不会返回虚拟值(因为用户可能期望它们具有某些含义)。

【讨论】:

  • 对我来说仍然是一个谜,这么多的人似乎对 C++ 标准了如指掌。这正是我一直在寻找的答案。还要感谢@BenVoigt 提供了一个很好的例子来说明它的应用。
  • @a.peganz:绝对不知道标准。但它组织得很好,所以找东西并不难。查找内容时只需使用最新版本:stackoverflow.com/a/4653479/14065
【解决方案2】:

这对于完美转发很有用。想象一下,你有一个类型的函子(模板参数),所以返回类型可能是任何东西。这种返回 void 类型值的权限允许您调用函子并将其返回值公开给调用者,而无需为没有返回值的情况编写单独的代码。

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)...);
}

这已经很乱了,但如果不是因为能够使用 return 关键字传播 void 返回类型,您需要两个由 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)...);
}

所以,return function_returning_void(); 是为特殊情况而设计的,它很有用。不要因为有可能就觉得你必须在任何地方返回void 或任何其他类型的虚拟对象。例如,不要使用return void(); 或return -1;,而只需使用return;。

【讨论】:

    【解决方案3】:

    你怎么看,代码符合标准吗?

    是的,确实如此。在返回void 的函数中,如果表达式的类型是void,则可以在return 语句中使用表达式。如果它是对同样返回 void 的函数的调用。

    您宁愿返回虚拟整数以使代码更具可读性吗?还是无用的返回值会使代码更难阅读?

    我认为虚拟整数不会使代码更具可读性。程序员期望返回值是有意义的。

    我认为更具可读性的是将函数调用和返回拆分为单独的语句:

    cleanup();
    return;
    

    虽然我承认,但这完全是见仁见智。

    【讨论】:

    • 缺少的表达式不是void 类型的表达式。除此之外,我完全同意。
    • @BenVoigt 我现在将文本回滚到以前的版本,在那里我没有提出这样的要求。出于某种原因,我认为如果缺少的表达式确实返回 void 并假设是这种情况,那么制定语法会更简单。我的立场是正确的。
    【解决方案4】:

    如果一个函数不返回任何值,那么检查该函数是否成功地完成了它必须做的事情会更明智。一个小例子:

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

    那么你就可以得到 foo() 的返回值了:

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

    【讨论】:

      猜你喜欢
      • 2017-07-13
      • 2015-01-24
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 2015-01-12
      • 1970-01-01
      • 2023-01-28
      • 1970-01-01
      相关资源
      最近更新 更多