如何通过指向函数的指针调用具有默认参数的函数,该函数是另一个函数的return?

How to call a function with default parameter through a pointer to function that is the return of another function?

我有函数 Mult, Add, Div, Sub, Mod 接受两个整数和 returns 其参数的结果。函数 Calc 将字符作为 Operator 和 returns 指向函数的指针 returns 一个整数并采用两个整数参数,如 Mult.

但它不适用于指向函数的指针:

int Add(int x, int y = 2) { // y is default
    return x + y;
}

int Mult(int x, int y = 2) { // y is default
    return x * y;
}

int Div(int x, int y = 2) { // y is default
    return y ? x / y : -1;
}

int Sub(int x, int y = 2) { // y is default
    return x - y;
}

int Mod(int x, int y = 2) { // y is default
    return y ? x % y : -1;
}

using pFn = int(*)(int, int);


pFn Calc(char c) {
    switch (c) {
        case '+':
            return Add;
        case '*':
            return Mult;
        case '/':
            return Div;
        case '-':
            return Sub;
        case '%':
            return Mod;
    }
    return Mult;
}

int main(int argc, char* argv[]){

    pFn func = Calc('%');
    cout << func(7, 4) << endl; // ok
    //cout << func(7) << endl; // error:  Too few arguments
    cout << Mult(4) << endl; // ok. the second argument is default

    func = Calc('/'); // ok
    cout << func(75, 12) << endl; // ok

    std::cout << std::endl;
}

上面如果我用一个参数调用 Mult 它工作正常,因为第二个参数是默认的但是通过指针调用它 func 它失败了。 func 是指向函数的指针,它接受两个整数和 returns 一个 int.

默认参数是一些 C++ 语法糖;当直接调用参数不足的函数时,编译器会插入默认值,就好像调用者已显式传递它一样,因此函数仍会使用完整的参数调用(Mult(4) 被编译成与 Mult(4, 2) 在这种情况下)。

虽然默认值实际上不是函数类型的一部分,因此您不能将默认值用于间接调用;语法糖在那里分解了,因为一旦您通过指针调用,有关默认值的信息就会丢失。

关于 "why not" 我建议你参考 。如果你想以某种方式保持使用默认值的能力,你需要提供比函数指针更多的东西,例如 lamdba 会做:

auto Double() {
    return [](int x,int y=2){ return Mult(x,y); };
}

并且通过使用可变 lambda(感谢@Artyer),您甚至不必重复默认值:

#include <iostream>

int Mult(int x, int y = 2) { // y is default
    return x * y;
}

auto Double() {
    return [](auto... args) { return Mult(args...); };
}

int main(int argc, char* argv[]){    
    auto func = Double();
    std::cout << func(7, 4) << '\n'; // ok
    std::cout << func(7) << '\n';    // ok
    std::cout << Mult(4) << '\n';    // ok
}

Live demo

如果您始终将 2 作为默认参数,则可以将您的函数指针包装到一个简单的助手 class 中,如下所示:

using pFn_ = int(*)(int, int);

class pFn
{
    pFn_ ptr;
public:
    pFn(pFn_ p) : ptr(p) {}
    int operator()(int x, int y = 2) const {
        return ptr(x,y);
    }
};

完整的工作示例:https://godbolt.org/z/5r7tZ8