默认参数和函数指针作为函数参数C++

Default parameter and function pointer as function arguments C++

本文关键字:参数 函数 C++ 指针 默认      更新时间:2023-10-16

我有一个函数,它接受参数,默认参数,最后,一个指向另一个函数的指针和一个空指针。

例如,请考虑以下内容

int foo(double arg 1, bool arg 2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*), void* data=0);

在我的代码库中的几个地方调用了它。我注意到,当函数指针本身有参数时,然后是默认参数,即使我想要的值是默认参数,也必须指定默认参数。例如,以下代码将编译

foo(arg1, arg2, pbar);

但下面的代码片段不会

foo(arg1, arg2, pbar, (void*) myint);

作为一个更完整的示例,下面是一个工作片段。

#include <iostream>
using namespace std;
int foo(double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0)
{
return 1;
}

bool bar(bool bt, void* vs)
{
return false;
}
int main()
{
double arg1 = 0.0;
bool arg2 = false;
bool bt = true;
int i = 1;
void* vs = &i;
bool pbar = bar(bt, vs);
// no defaults specified and no function pointer arguments
foo(arg1, arg2, pbar);
// specify one of the defaults
int arg3 = 23;
foo(arg1, arg2, arg3, pbar);
// don't specify the defaults, but give arguments to function pointer
//foo(arg1, arg2, pbar, bt, vs);

return 0;
}

最终注释的调用将不会编译。

所以我的问题是,为什么在函数指针参数的规范下无法编译?

我已经通过使用"命名参数"方法找到了解决问题的方法。借此我创建一个类并使用引用实例化成员。但是,我对上述失败的原因进行深入解释感兴趣。

错误如下所示

main.cpp: In function ‘int main()’:
main.cpp:41:33: error: invalid conversion from ‘void*’ to ‘bool (*)(bool, void*)’ [-fpermissive]
foo(arg1, arg2, pbar, bt, vs);
^
main.cpp:13:5: note:   initializing argument 5 of ‘int foo(double, bool, int, int, bool (*)(bool, void*), void*)’
int foo(double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0)
^~~

我相信这是因为参数的顺序搞砸了。但是,为什么我可以插入函数指针而不担心默认的 arg3 和 arg4?

int foo(double arg1, bool arg2, int arg3 = 0, int arg4 = 2, bool * pbar(bool , void *) = 0, void * data = 0);

编译器只关心参数的顺序

不能跳过定义 arg3 和 arg4,因为它们具有默认值。

通过这样做:

foo(arg1, arg2, pbar);

你基本上是在传递"pbar"(这是一个函数(,其中"arg3"应该是(这是一个整数(

所以我的问题是,为什么在函数指针参数的规范下无法编译?

它无法编译您传递的参数具有错误的类型。参数的类型是指向函数的指针。您正在传递一个void*,这是一个对象指针。void*不能隐式转换为指向函数的指针。

int foo(
double arg1, bool arg2, int arg3=0, int arg4=2, bool (*pbar)(bool,void*)=0, void* data=0)
1          2         3           4    ^^^^^^^^^ 5 ^^^^^^^^^^^^
pointer to function

void* vs = &i;
^^^^^ not a pointer to function
foo(arg1, arg2, pbar, bt, vs);
1     2     3   4  ^5

参数仍然必须按正确的顺序排列。然后,您可以选择要包含的可选参数数量,但请注意,不能跳过任何可选参数。

所以在你的例子中,foo(arg1, arg2, pbar(工作是因为pbar不是一个函数,它只是一个布尔值。 bar(( 返回 false,因此 pbar 将被设置为 0,然后在执行 foo(arg1, arg2, pbar( 时将其转换为整数,因为第三个参数是整数,所以这就是它工作的原因。

与第二个调用 foo(arg1, arg2, arg3, pbar 相同(,pbar 仍然只有 0。

注释的调用返回错误,因为如前所述,您无法跳过可选参数,因此 foo(arg1, arg2, pbar, bt, vs( 将传入 vs(一个 void 指针(作为函数指针。如果要包含特定的可选参数,则必须在该参数之前指定所有参数。

默认参数背后的基本原则是它们适用于参数列表中最右侧的参数。

void f(int, double = 0, void* = 0); // okay
void g(int, double = 0, void*); // error: third argument needs a default value

同样,当使用默认参数调用函数时,只有最右侧的参数获取其默认值:

f(3); // okay; second and third arguments get default values
f(3, 1.0); // okay; third argument gets default value
int x;
f(3, 1.0, &x); // okay; no default arguments used

你不能跳过参数,即使可以确定你的意思是哪一个:

f(3, &x); // illegal: second argument has type double, and &x can't be converted to double

如果其中一个参数可转换为适当的类型,这可能会令人困惑,并且看起来这可能是编译问题中的代码中发生的情况。例如

void h(int, bool = false, int* = 0);
int x;
h(3, &x);   // okay; &x gets converted to bool
h(3, true); // same as the previous one
h(3, false, &x); // okay, all three arguments provided