将默认参数的函数作为参数传入函数。

5

我知道你可以像这样将函数作为参数传递:

int a(int x) {
    return x + 1;
}

int b(int (*f)(int), int x) {
    return f(x); // returns x + 1
}

我知道你也可以创建默认参数的函数,就像这样:

int a(int x = 1) {
    return x;
}

a(2); // 2
a();  // 1

然而,如何将带有默认参数的函数传递给另一个函数并保留这种行为呢?

我尝试了以下方法:

int b(int (*f)(int), int x) {
    f(x); // works as expected
    f();  // doesn't work because there aren't enough arguments to f
}

int b(int (*f)()) {
    f();  // doesn't work because it cannot convert int (*)(int) to int (*)()
}

1
这将会很棘手,因为默认参数是一个编译时操作。编译器看到定义int a(int x = 1)后,会把你的a();转换成a(1);并编译它。 - Drew Dormann
1
默认参数在编译时根据编译器所能看到的内容应用于调用站点。如果编译器无法百分之百确定函数指针的另一端是什么函数,就几乎没有办法应用默认参数。即使只使用一个函数,该函数在代码的不同点可能具有不同的声明,并带有不同的默认参数或这些参数的值。因此,我不会感到惊讶,如果编译器甚至不尝试解决它。 - user4581301
2
@DrewDormann 哦,我明白了,那很有道理。谢谢,我可能会通过创建可调用对象来规避这个问题。 - hyper-neutrino
2
在C++中,我认为可调用对象应该是优先选择而不是函数指针。函数指针不携带状态,并且除了基本的“C”功能外,您无法对它们执行任何操作。使用可调用对象,您基本上可以做任何事情,包括将整个参数确定过程从调用调用站点移开,这都归功于operator()。这是您无法使用“愚蠢”的函数指针完成的事情。 - PaulMcKenzie
1
默认参数不是签名的一部分。因此,您无法区分例如void f(int=0)void g(int=1)之间的差异。您将不得不将函数与默认参数一起包装。 - zdf
显示剩余3条评论
2个回答

3

使用函数指针无法实现此操作,因为函数指针不能存储默认参数的信息。但是,您可以传递一个带有默认参数成员函数的函数对象。

a 转换为这样的对象很简单; 只需将其变为 lambda 函数即可。

auto a = [](int x = 1) {
    // ...
};

然后b可以接受一个函数对象,其中类型被推断出来

template<typename F>
int b(F f, int x) {
    f(x);  // ok
    f();   // also ok, default value is 1
}

这里有一个演示


3

使用函数指针无法转发默认参数值。

但是,如果可以将b转换为模板函数,则可以使其正常工作:

通过在operator()中使用参数包并显式调用a,我们给编译器机会在需要时应用默认参数值:

int a(int x = 12) {
    return x + 1;
}

template<class T>
int b(T f, int x) {
    return f() + f(x);
}

struct AFnWrapper {
    template<class... Args>
    auto operator()(Args&&... args) {
        return a(std::forward<Args>(args)...);
    }
};

int main() {
   std::cout << b(AFnWrapper{}, 1) << std::endl; // 15
}

这可以用一个 lambda 函数来简化:
std::cout << b([](auto&&... args) { return a(std::forward<decltype(args)>(args)...); }, 1) << std::endl;

如果您不需要完美转发,可以让它更短:

std::cout << b([](auto... args) { return a(args...); }, 1) << std::endl;

godbolt示例


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接