将类中声明的函数作为参数传递会导致编译错误

Passing a function declared in class as arguments causes compilation error

本文关键字:参数传递 错误 编译 声明 函数      更新时间:2023-10-16

我遇到了将函数指针作为参数传递的问题。

指向函数类型的指针声明:

typedef void(*cbk_fct)(void);

Operation有一个构造函数,该构造函数接受cbk_fct作为参数,声明如下所示:

class Operation
{
 private:
 cbk_fct m_fct_ptr;
public:
 Operation(cbk_fct fct_ptr);
};
Operation::Operation(cbk_fct fct_ptr):
m_fct_ptr(fct_ptr)
{
}

现在类User将调用Operation的构造函数

class User
{
 public:
 User();
 void userOperation();
};
void User::userOperation()
{
 cout << "User operation"<<endl;
}
User::User()
{
 Operation op(userOperation); // This version doesnt work
}

此调用将给出以下错误:

no matching function for call to 'Operation::Operation(<unresolved overloaded function type>)'|
no known conversion for argument 1 from '<unresolved overloaded function type>' to 'cbk_fct {aka void (*)()}'

但是,如果我声明该函数作为参数传递到类外部,它将被接受

void UserOperationNotInClass()
{
 cout << "User operation"<<endl;
}
User::User()
{
 Operation op(UserOperationNotInClass); // This version works
}

显然,错误消息提到它无法从"转换为"cbk_fct",但是这种类型的"未解决的重载函数类型"从何而来

非静态成员函数与普通函数不同。具体来说,它可以this指针访问其对象,这对于普通函数没有意义。因此,当编译器说没有从前者到后者的已知转换时,编译器是正确的。

与自由函数不同,没有从成员函数到成员函数的指针的隐式转换,因此您永远无法提供userOperation。你必须使用&User::userOperation.在这方面,错误消息可能会更好。

修复后,&User::userOperation的类型为 void (User::*)(void) ,这与void (*)(void)(您的别名cbk_fct)不同。你总是需要一个User来打电话给userOperation,而且没有地方可以。如果您希望Operation包含成员函数,则必须更改它。

(C 兼容)C++98 方法是在函数类型和 Operation 的成员中都包含一个void *,并传递this(或任何其他对象指针),隐式转换为 void *

typedef void * context_ptr;
typedef void (* action_ptr)(context_ptr);
class Operation
{
 private:
 action_ptr m_action;
 context_ptr m_context;
public:
 Operation(action_ptr action, context_ptr context);
};
Operation::Operation(action_ptr action, context_ptr context):
m_action(action), m_context(context)
{}
class User
{
 static void callUserOperation(context_ptr);
 public:
 User();
 void userOperation();
};
void User::callUserOperation(context_ptr context)
{
    User * user = reinterpret_cast<User *>(context);
    user->userOperation();
}
void User::userOperation()
{
 cout << "User operation"<<endl;
}
User::User()
{
 Operation op(&User::callUserOperation, this);
}

在 C++11 中,您可以使用 std::function 来保存特定签名的任何函数对象,并从捕获this和调用userOperation的 lambda 构造它

using action_ptr = std::function<void(void)>;
class Operation
{
 private:
 action_ptr m_action;
public:
 Operation(action_ptr action);
};
Operation::Operation(action_ptr action):
m_action(action)
{}
class User
{
 public:
 User();
 void userOperation();
};
void User::userOperation()
{
 cout << "User operation"<<endl;
}
User::User()
{
 Operation op([this]{ userOperation(); });
}