C++ 为什么要在最后添加默认参数 功能?

发布于 2024-07-27 18:08:09 字数 28 浏览 9 评论 0原文

为什么 C++ 函数中默认参数要放在最后?

Why should default parameters be added last in C++ functions?

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

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

发布评论

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

评论(9

舂唻埖巳落 2024-08-03 18:08:09

简化语言定义并保持代码可读性。

void foo(int x = 2, int y);

要调用它并利用默认值,您需要这样的语法:

foo(, 3);

这可能被认为太奇怪了。 另一种替代方法是在参数列表中指定名称:

foo(y : 3);

必须使用新符号,因为这已经意味着某种意义:

foo(y = 3); // assign 3 to y and then pass y to foo.

ISO 委员会考虑并拒绝了这种命名方法,因为他们对在参数名称之外引入新的含义感到不舒服。函数定义。

如果您对更多 C++ 设计原理感兴趣,请阅读 C++ 的设计和演变 斯特鲁斯特鲁普。

To simplify the language definition and keep code readable.

void foo(int x = 2, int y);

To call that and take advantage of the default value, you'd need syntax like this:

foo(, 3);

Which was probably felt to be too weird. Another alternative is specifying names in the argument list:

foo(y : 3);

A new symbol would have to be used because this already means something:

foo(y = 3); // assign 3 to y and then pass y to foo.

The naming approach was considered and rejected by the ISO committee because they were uncomfortable with introducing a new significance to parameter names outside of the function definition.

If you're interested in more C++ design rationales, read The Design and Evolution of C++ by Stroustrup.

莳間冲淡了誓言ζ 2024-08-03 18:08:09

如果定义以下函数:

void foo( int a, int b = 0, int c );

如何调用该函数并为 a 和 c 提供值,但将 b 保留为默认值?

foo( 10, ??, 5 );

与某些其他语言(例如 Python)不同,C/C++ 中的函数参数不能按名称限定,如下所示:

foo( a = 10, c = 5 );

如果可能,则默认参数可以位于列表中的任何位置。

If you define the following function:

void foo( int a, int b = 0, int c );

How would you call the function and supply a value for a and c, but leave b as the default?

foo( 10, ??, 5 );

Unlike some other languages (eg, Python), function arguments in C/C++ can not be qualified by name, like the following:

foo( a = 10, c = 5 );

If that were possible, then the default arguments could be anywhere in the list.

美胚控场 2024-08-03 18:08:09

想象一下您有一个具有以下原型的函数:

void testFunction(bool a = false, bool b = true, bool c);

现在假设我这样调用该函数:

testFunction(true, false);

编译器应该如何确定我打算为其提供值的参数?

Imagine you had a function with this prototype:

void testFunction(bool a = false, bool b = true, bool c);

Now suppose I called the function like this:

testFunction(true, false);

How is the compiler supposed to figure out which parameters I meant to supply values for?

时光磨忆 2024-08-03 18:08:09

正如大多数答案所指出的那样,在参数列表中的任何位置可能存在默认参数都会增加函数调用的复杂性和歧义性(对于编译器而言,对于函数的用户来说可能更重要)。

C++ 的一个好处是,通常有一种方法可以实现您想要的功能(即使这并不总是一个好主意)。 如果您想为各种参数位置提供默认参数,则几乎可以肯定可以通过编写重载来实现这一点,只需简单地转身并内联调用完全参数化函数即可

 int foo( int x, int y);
 int foo( int y) {
     return foo( 0, y);
 }

 int foo( int x = 0, int y);

As most of the answers point out, having default parameters potentially anywhere in the parameter list increases the complexity and ambiguity of function calls (for both the compiler and probably more importantly for the users of the function).

One nice thing about C++ is that there's often a way to do what you want (even if it's not always a good idea). If you want to have default arguments for various parameter positions, you can almost certainly do this by writing overloads that simply turn around and call the fully-parameterized function inline:

 int foo( int x, int y);
 int foo( int y) {
     return foo( 0, y);
 }

And there you have the equivalent of:

 int foo( int x = 0, int y);
安稳善良 2024-08-03 18:08:09

作为一般规则,函数参数由编译器处理并按从右到左的顺序放置在堆栈中。 因此,首先评估任何具有默认值的参数是有意义的。

(这适用于 __cdecl,它往往是 VC++ 和 __stdcall 函数声明的默认值)。

As a general rule function parameters are processed by the compiler and placed on the stack in right to left order. Therefore it makes sense that any parameters with default values should be evaluated first.

(This applieds to __cdecl, which tends to be the default for VC++ and __stdcall function declarations).

⒈起吃苦の倖褔 2024-08-03 18:08:09

这是因为它使用参数的相对位置来查找它们对应的参数。

它可以使用类型来识别未给出可选参数。 但隐式转换可能会干扰它。 另一个问题是编程错误,这些错误可能被解释为可选参数丢失,而不是丢失参数错误。

为了允许任何参数成为可选的,应该有一种方法来识别参数以确保没有编程错误或消除歧义。 这在某些语言中是可能的,但在 C++ 中则不行。

Its because it uses the relative position of arguments to find to which parameters they correspond.

It could have used the types to identify that an optional parameter was not given. But implicit conversion could interfere with it. Another problem would be programming errors that could be interpreted as optional arguments drop out instead of missing argument error.

In order to allow any argument to become optional, there should be a way to identify the arguments to make sure there is no programming error or to remove ambiguities. This is possible in some languages, but not in C++.

想你的星星会说话 2024-08-03 18:08:09

标准委员会必须考虑的另一件事是默认参数如何与其他功能交互,例如重载函数、模板解析和名称查找。 这些功能已经以非常复杂且难以描述的方式相互作用。 让默认参数能够出现在任何地方只会增加复杂性。

Another thing that the standards committee had to consider was how default parameters interacts with other features, like overloaded functions, template resolution, and name lookup. These features interact in very complex and hard to describe ways already. Making default parameters be able to appear anywhere would only increase the complexity.

花之痕靓丽 2024-08-03 18:08:09

这是一个关于调用约定的问题。
调用约定:
当调用函数时,参数从右到左压入堆栈。
例如

fun(int a, int b, int c);

堆栈是这样的:
A

C
因此,如果您像这样从左到右设置默认值:

fun(int a = 1, int b = 2, int c);

并像这样调用:

fun(4,5);

您的调用意味着设置 a = 4、b = 5 和 c = 无值; //这是错误的!

如果您像这样声明函数:

fun(int a, int b = 2, int c = 3);

并像这样调用:
fun(4, 5);

你的调用意味着设置 a = 4、b = 5 和 c = 默认值(3); // 哪个是对的!

总之,您应该将默认值从右向左放置。

It is a matter about call convention.
Call Convention:
When you call a function, the parameters are pushed in stack from right to left.
e.g.

fun(int a, int b, int c);

the stack is like this:
a
b
c
so, if you set the default value from left to right like this:

fun(int a = 1, int b = 2, int c);

and call like this:

fun(4,5);

your call means set a = 4, b = 5, and c = no value; // which is wrong!

if you declare the function like this:

fun(int a, int b = 2, int c = 3);

and call like this:
fun(4, 5);

your call means set a = 4, b = 5, and c = default value(3); // which is right!

In conclusion, you should put the default value from right to left.

晨敛清荷 2024-08-03 18:08:09

曾静说得对。 我想在这里补充一下我的看法。 当调用函数时,参数从右到左压入堆栈。 例如,假设您有这个任意函数。

int add(int a, int b) {
  int c;
  c = a + b;
  return c;
}

这是该函数的堆栈帧:

------
  b
------
  a
------
 ret
------
  c
------

上图是该函数的堆栈帧! 正如你所看到的,首先b被压入堆栈,然后a被压入堆栈。 之后函数返回地址被压入堆栈。 函数返回地址保存了 main() 中函数最初被调用的位置,函数执行完毕后,程序的执行将转到该函数的返回地址。 然后,任何局部变量(例如 c)都会被推入堆栈。

现在关键是参数从右到左压入堆栈。 基本上,提供的任何默认参数都是文字值,它们存储在可执行文件的代码部分中。 当程序执行遇到没有相应参数的默认参数时,它会将该文字值推送到堆栈顶部。 然后它查看 a 并将参数的值推入堆栈顶部。 堆栈指针始终指向堆栈顶部,即最近推送的变量。 因此,作为默认参数压入堆栈的任何文字值都位于堆栈指针“后面”。

对于编译器来说,首先快速将任意默认文字值推入堆栈可能更有效,因为它们不存储在内存位置,然后快速构建堆栈。 想想如果先将变量压入堆栈,然后再压入文字,会发生什么。 与从电路或 CPU 寄存器中提取文字值相比,访问 CPU 的内存位置需要相对较长的时间。 由于与文字相比,将变量压入堆栈需要更多时间,因此文字必须等待,然后返回地址必须等待,局部变量也必须等待。 在效率方面这可能不是一个大问题,但这只是我的理论,为什么默认参数总是位于 C++ 函数头的最右边位置。 这意味着编译器就是这样设计的。

Jing Zeng is correct. I would like to add my remarks here. When a function is called, the arguments are pushed onto the stack from right to left. For example, let's say you have this arbitrary function.

int add(int a, int b) {
  int c;
  c = a + b;
  return c;
}

Here is the stack frame for the function:

------
  b
------
  a
------
 ret
------
  c
------

This diagram above is the stack frame for this function! As you can see, first b is pushed onto the stack, then a is pushed onto the stack. After that the function return address is pushed onto the stack. The function return address holds the location in main() from where the function was originally called, and after the function is done executing, the execution of the program goes to that function's return address. Then any local variables such as c are pushed onto the stack.

Now the key thing is that arguments are pushed onto the stack from right to left. Basically any default parameters that are supplied are literal values, which are stored in the code section of an executable. When the program execution encounters a default parameter without a corresponding argument, it pushes that literal value onto the top of the stack. Then it looks at a and pushes the argument's value onto the top of the stack. The stack pointer always points to the top of the stack, your most recently pushed variable. So any literal values you pushed onto the stack as default parameters are "behind" the stack pointer.

It was probably more efficient for the compiler to quickly first push arbitrary default literal values onto the stack first, since they're not stored in a memory location, and build up the stack quickly. Think about what would have been if the variables would have been pushed onto the stack first, and then the literals. Accessing a memory location for the CPU takes up a relatively long time compared to pulling a literal value out of a circuit or CPU register. Since it takes more time to push variables onto the stack vs. literals, the literals would have to wait, then the return address would have to wait, and the local variables would have to wait as well. It's probably not a big concern in efficiency, but that's just my theory for why default arguments are always in the rightmost positions of a function header in C++. It means that the compiler was designed as such.

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