如何创建不同原型的函数指针数组?

vc6*_*669 28 c++ oop function c++14

我有一些像这样定义的函数:

ParentClass*    fun1();
ParentClass*    fun2();
ParentClass*    fun3(bool inp=false);
ChildClass*     fun4();
ChildClass*     fun5(int a=1, int b=3);
Run Code Online (Sandbox Code Playgroud)

我想将它们放入如下的某种数组中:

void* (*arr[5])() = {
    (void* (*)())fun1,
    (void* (*)())fun2,
    (void* (*)())fun3,
    (void* (*)())fun4,
    (void* (*)())fun5
}
Run Code Online (Sandbox Code Playgroud)

现在我想简单地使用这个函数数组

for(int i=0; i<5; i++)
    someFunction(arr[i]());
Run Code Online (Sandbox Code Playgroud)

现在我在这里意识到问题是void* (*arr[5])(),但鉴于我只想使用函数而不提供参数,我希望所有这些都是同一个数组的一部分.

不过,这些都是非常C风格的方式.有没有更好的方法来使用C++中的模板?

Que*_*tin 42

C风格与否,你所拥有的是直接未定义的行为.使用lambdas:

void (*arr[5])() = {
    [] { fun1(); },
    [] { fun2(); },
    [] { fun3(); },
    [] { fun4(); },
    [] { fun5(); }
};
Run Code Online (Sandbox Code Playgroud)

这些都没关系,因为它们通过函数的正确类型执行调用,并且它们本身可以转换为void (*)().

转发返回的值足够简单,因为lambda为转换提供了上下文.在你的情况下,因为ChildClass所谓的继承ParentClass,隐式转换就足够了:

ParentClass *(*arr[5])() = {
    []() -> ParentClass * { return fun1(); },
    []() -> ParentClass * { return fun2(); },
    []() -> ParentClass * { return fun3(); },
    []() -> ParentClass * { return fun4(); },
    []() -> ParentClass * { return fun5(); }
};
Run Code Online (Sandbox Code Playgroud)


dat*_*olf 16

但鉴于我只想使用函数而不提供参数

它根本不起作用.你有没有想过,那么当你把函数声明放在标题中时,为什么你必须在标题中写入默认参数而不能将它放在实现源文件的定义中?

这是因为默认参数实际上并非"嵌入"到函数中,而是由编译器用于在调用位置用这些参数扩充函数调用,其中省略这些参数.(编辑:另外,由于@Aconcagua在评论中如此敏锐地观察到,因为默认参数通常被定义为标题函数声明的一部分,所以默认值的任何更改都需要对包含这些标题的任何编译单元进行完全重新编译,ergo函数声明,让更改真正生效!)

虽然完全有可能做一些非常奇怪的类型转换疯狂来构造像这样的函数指针数组,但最终你必须回转到原始函数调用签名,以便不调用未定义的行为.

如果你需要绑定函数指针,以及一些抽象出调用的类型的默认参数,它确实提供了参数,并向外部提供了一个多态接口.所以你有一个std::vector<function_binder>function_binder[]哪里的功能绑定器有一个operator()调用该功能.

但是当你首先进行绑定时,你可以将它绑定在一个匿名函数中,即lambdas.在lambda instanciation时,默认参数被绑定.

std::vector<void(*)()> fvec = {
    []{ func0(); },
    []{ func1(); },
    []{ func2(); },
}
Run Code Online (Sandbox Code Playgroud)


Det*_*nar 9

您可以使用 std::bind

std::function<ParentClass *(void)> arr[5] = {
    std::bind(&fun1),
    std::bind(&fun2),
    std::bind(&fun3, false),
    std::bind(&fun4),
    std::bind(&fun5, 1, 3)
};
Run Code Online (Sandbox Code Playgroud)

现在你可以做到

for(int i=0; i<5; i++)
    arr[i]();
Run Code Online (Sandbox Code Playgroud)

您必须确保绑定所有函数的每个函数参数.

这也适用于成员函数.您只需将对象引用(例如this)绑定为第一个参数.

  • 我的口味是`std :: bind`,因为如果强迫不那么有纪律的开发人员编写小函数.Lambda经常被过度使用并逐渐增长到嘲笑大小,但它仍然更容易使用,而且速度更快.`std :: bind`创建了复杂的模板,在分析崩溃日志时很烦人. (2认同)