在返回 void 的函数中,为什么要返回 void 表达式而不是省略 return 语句?

发布于 2024-09-13 12:50:41 字数 270 浏览 3 评论 0原文

考虑以下代码片段:

void Foo()
{
  // ...
}

void Bar()
{
  return Foo();
}

与更常见的方法相比,在 C++ 中使用上述内容的合理理由是什么:

void Foo()
{
  // ...
}

void Bar()
{
  Foo();

  // no more expressions -- i.e., implicit return here
}

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
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

把时间冻结 2024-09-20 12:50:41

在您的示例中可能没有用,但在某些情况下很难在模板代码中处理 void ,我希望此规则有时会有所帮助。非常人为的示例:

#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>();
}

请注意,只有 main 必须处理这样的事实:在 void 情况下, retval 没有任何内容可返回。中间函数do_something_and_return是通用的。

当然,这只能让你到目前为止 - 如果在正常情况下 do_something_and_return 想要将 retval 存储在变量中并在返回之前对其执行某些操作,那么你会仍然有麻烦 - 你必须专门化(或重载)do_something_and_return for void。

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.

计㈡愣 2024-09-20 12:50:41

这是一个相当无用的结构,除非与模板一起使用,否则没有任何作用。也就是说,如果您定义的模板函数返回的值可能为“void”。

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

始终不够 2024-09-20 12:50:41

您可以在通用代码中使用它,其中 Foo() 的返回值未知或可能会更改。考虑:

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

在这种情况下,Bar 对于 void 有效,但如果返回类型更改也有效。然而,如果它只是调用 f,那么如果 T 是非空的,这段代码就会中断。使用 return f();语法保证保留 Foo() 的返回值(如果存在),并且允许使用 void()。

此外,明确返回是一个值得养成的好习惯。

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.

緦唸λ蓇 2024-09-20 12:50:41

模板:

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

如果无法返回 void,则当要求包装 func2 时,模板中的 return func(t) 将无法工作。

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.

旧情别恋 2024-09-20 12:50:41

我能想到的唯一原因是,如果您在 switch 中有一长串 return Foo(); 语句,并且希望使其更加紧凑。

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.

黯淡〆 2024-09-20 12:50:41

可能是 Foo() 最初返回一个值,但后来改为 void,而更新它的人只是想得不太清楚。

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.

逆夏时光 2024-09-20 12:50:41

首先也是最重要的,在编写模板时返回 void 会很有帮助。
如果您知道函数返回 void,您通常不会这样做,但它是合法的会很有帮助:

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

这个示例可能有点人为,但实际上,返回 void > 简化了 std::apply 的实现。

另一个用例是使 switch 语句更加紧凑:

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

从技术上讲,before 每个案例也可以只有一行,但是将多个语句放在一行上通常会与样式指南发生冲突,并且/或自动格式化程序。

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.

九厘米的零° 2024-09-20 12:50:41

原因是返回内存,就像 math.h 总是返回一样。 math.h 没有 void 也没有空参数。有许多实际情况需要记忆。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文