C++ 将类成员函数作为参数从同一类的另一个成员函数中传递

C++ 将类成员函数作为参数从同一类的另一个成员函数中传递,c++,c++11,c++14,C++,C++11,C++14,我提供了一个我正在处理的问题的简单版本 我有一个类实体,它有一个用户对象的映射。为了简单起见,我只添加了一个elementname。我已经围绕userMap对象实现了getter和setter 包装器函数对于我来说是必需的,因为它可以处理多线程的情况。这里没有显示。我通过几个这样的线程实现了一个工作示例 但正如您所看到的,在过程函数中使用包装函数时,我必须在三个位置编写id、arg tuple参数。是否有一种方法可以实现相同的功能,方法是为函数参数设置某种占位符,以便调用包装器看起来很干净,即w

我提供了一个我正在处理的问题的简单版本

我有一个类实体,它有一个用户对象的映射。为了简单起见,我只添加了一个elementname。我已经围绕userMap对象实现了getter和setter

包装器函数对于我来说是必需的,因为它可以处理多线程的情况。这里没有显示。我通过几个这样的线程实现了一个工作示例

但正如您所看到的,在过程函数中使用包装函数时,我必须在三个位置编写id、arg tuple参数。是否有一种方法可以实现相同的功能,方法是为函数参数设置某种占位符,以便调用包装器看起来很干净,即wrapper1、static_cast&name、function_ptr


谢谢

在我看来,我认为你强迫使用lambda是在给自己制造麻烦,我知道它们很有趣,但通常不是很有用。一般来说,保持简单的愚蠢之吻,在你的情况下,只需将函数分为两个单独的函数

class Entity {
    public:
        ...            
        void getUserName(int id,void * arg);
        void setUserName(int id,void * arg);
        void procedure();
        void criticalTask(int id); // critical task, based on id
};

void Entity::getUserName(int id,void *arg) {...}

void Entity::setUserName(int id,void *arg) {...}

void Entity::criticalTask(int id) {
    cout <<"\nSome Other critical task based on id"<< endl;
}

void Entity::procedure() {
    cout <<"Procedure starts"<<endl;

    ...

    criticalTask(id);
    getUserName(id, &name);

    ...

}

int main() {
    Entity E;
    E.procedure();
}

我将从一个直接的答案开始,但请继续阅读下面的警告

对于您尝试执行的操作,更简单的语法是将第三个参数的类型更改为wrapper。与其将成员函数转换为非成员函数,不如将成员函数作为参数

void wrapper(int id, void* arg, void (Entity::* func)(int,void*))
{
    cout <<"\nSome Other critical task based on id"<< endl;
    (this->*func)(id, arg);
}
这样您的通话就会变得更简单:

wrapper(1, static_cast<void*>(&name), &Entity::getUserName);
wrapper(1, static_cast<void*>(&name), &Entity::setUserName);
然而,这真的是你想要采取的方法吗?您依赖于人们记住调用包装器,而不是直接调用其他成员函数。如果你在某个时候忘记使用包装器,你能根据症状找出原因吗?你想试试吗

一种更健壮的方法是将关键任务放在它自己的函数中,然后让getter和setter调用它。更像是:

void criticalStuff(int id)
{
    cout <<"Some critical task based on id\n";
}

void Entity::getUserName(int id, string & arg)
{
    criticalStuff(id); // Critical stuff first.

    auto iter = userMap.find(id);
    if(iter != userMap.end()) {
        arg = iter->second.name; 
    }
}

void Entity::setUserName(int id, const string & arg)
{
    criticalStuff(id); // Critical stuff first.

    auto iter = userMap.find(id);
    if(iter != userMap.end()) {
        iter->second.name = arg;
    }
}

任何添加新字段的人在编写新的getter和setter时都必须记住关键内容,但更常见的情况是调用这些函数会自动处理关键内容。此外,您还可以恢复参数的类型检查,因为似乎不再有理由将内容强制转换为void*

不是,例如wrapper1、static_cast&name、getUserName;通过隐式转换完成工作。只是一个未经检验的想法@科尔尼。它显示,无效使用非静态成员函数“void Entity::getUserNameint,void*”错误。它不适用于类成员函数。请考虑只使用类成员函数。@ DeBasHISH更新了我的答案-> GETUsReNEX是一个无效的非静态成员函数名称的使用。形成指向成员的指针的唯一方法是使用&Entity::getUserName语法。@aschepler您说得对,谢谢,刚刚删除了此部分。避免函数指针和lambdas也是更好的解决方案。define CALL_MEMBER_FNobject,ptrtomber object.*ptrtomber void Entity::wrapperint id,void*arg,void Entity::*funcint,void*{cout
wrapper(1, static_cast<void*>(&name), &Entity::getUserName);
wrapper(1, static_cast<void*>(&name), &Entity::setUserName);
void criticalStuff(int id)
{
    cout <<"Some critical task based on id\n";
}

void Entity::getUserName(int id, string & arg)
{
    criticalStuff(id); // Critical stuff first.

    auto iter = userMap.find(id);
    if(iter != userMap.end()) {
        arg = iter->second.name; 
    }
}

void Entity::setUserName(int id, const string & arg)
{
    criticalStuff(id); // Critical stuff first.

    auto iter = userMap.find(id);
    if(iter != userMap.end()) {
        iter->second.name = arg;
    }
}