【问题标题】:Difficulty in passing function pointer of a class member function难以传递类成员函数的函数指针
【发布时间】:2021-09-10 15:17:41
【问题描述】:

在尝试在我自己的上下文中实现建议的答案 here 时,我遇到了编译错误。

考虑代码:

#include <iostream>

class SIMPLE {
public:
    SIMPLE() { for (int i = 0; i < 5; i++) val[i] = 5; };
    int retval(int index) { return val[index]; }
private:
    int val[5];
};

void print_array_of_length5(int (*fnptr)(int index)){
    for (int i = 0; i < 5; i++)
        printf("%d ", fnptr(i));
}

int global_array[5] = { 0, 1, 2, 3, 4 };
int global_function(int index){
    return global_array[index];
}

int main(){
    print_array_of_length5(&global_function);//Works fine.
    int (SIMPLE::*p)(int) = &SIMPLE::retval;//Following method suggested in the answer above
    class SIMPLE smpl;
    print_array_of_length5(smpl.*p);//Compile error: a pointer to a bound function may only be used to call the function
}

当提供全局函数的地址时,该函数可以工作。通过smpl.*p 时它不起作用,类似于建议的方法。应该如何解决这个错误?

【问题讨论】:

  • print_array_of_length5 函数采用指向非成员函数的指针。
  • 你不能在没有实例的情况下调用非static 成员函数,并且print_array_of_length5 中没有可用的实例——你必须重新考虑你的整个方法

标签: c++ function-pointers member-function-pointers


【解决方案1】:

你需要另一个print_array_of_length5 的重载来传递一个成员函数指针:

template<typename T>
void print_array_of_length5(int (T::*fnptr)(int index), T& obj)
{
    for(int i = 0; i < 5; ++i)
    {
        printf("%d ", (obj.*fnptr)(i));
    }
}

int main()
{
    SIMPLE smpl;
    print_array_of_length5(&SIMPLE::retval, smpl);
}

【讨论】:

  • 我测试了这种方法并且它有效。但是,需要将 print_array_of_length5 中的代码复制两次——一次有一个参数,另一个有两个参数,你不觉得吗?在@NathanOliver 的回答中,似乎只需要维护一个功能。
  • 说到维护:@NathanOliver's 暗示需要类型验证,这足以让事情变得复杂。顺便说一句,问题中函数的用法不清楚。
【解决方案2】:

您不能将非静态成员函数指针作为常规函数指针传递。成员函数可以访问this 指针,它们获取的方式是通过一个不可见的隐式函数参数。您需要将调用函数的对象和函数本身绑定在一起,而函数指针根本无法做到这一点。

我们可以做的是把print_array_of_length5 做成一个函数模板,并允许它接受任何类型的可调用。这会给你这样的东西:

template <typename Function>
void print_array_of_length5(Function func){
    for (int i = 0; i < 5; i++)
        printf("%d ", func(i));
}

要使用非静态成员函数调用它,可以使用 lambda 表达式或 std::bind(),如下所示:

SIMPLE smpl;
print_array_of_length5([&smpl](int foo){ return smpl.retval(foo); });
using namespace std::placeholders;
SIMPLE smpl;
auto func = std::bind(&SIMPLE::retval, &smpl, _1);
print_array_of_length5(func);

【讨论】:

  • 我进一步研究了这个答案,试图在我更复杂的项目中实现这一点,我有一个OUTER 类,在其中一个方法中,一个不同的INNER 类对象的方法应该作为函数传递指针。我在那里遇到了编译问题。您是否可以查看此链接,该链接显示编译器错误以建议出路? godbolt.org/z/rG1oc86z5如果问的太多,我可以理解。我将在 SO 上发布一个新问题。
  • @Tryer 你忘了在定义中给函数参数命名:godbolt.org/z/MK3sGx1hY
  • 啊,是的。抱歉,我对模板等非常陌生。再次感谢您。
猜你喜欢
  • 2018-04-14
  • 1970-01-01
  • 2012-06-27
  • 1970-01-01
  • 1970-01-01
  • 2012-08-01
  • 2013-06-29
  • 2021-11-29
相关资源
最近更新 更多