问询:能否不使用this->*调用类成员函数指针?
成员函数指针调用的替代语法问题
我编写了一个用于查找关键字并执行关联成员函数的类,代码如下:
#include <iostream> #include <string> #include <map> class Example; typedef std::map< std::string, void (Example::*)(const std::string &)> ExampleList; typedef ExampleList::iterator ExampleIter; class Example { public: ExampleList lut; Example() { lut["aaa"] = &Example::aaa; lut["bbb"] = &Example::bbb; } void lookup(const std::string& line) { // 获取关键字 std::size_t keylen = line.find(' ', 0); std::string keyword = line; if (keylen != line.npos) keyword = line.substr(0, keylen); // 检查是否为已知关键字 ExampleIter eit = lut.find(keyword); if (eit == lut.end()) { std::cout << "无法处理关键字: " << keyword << std::endl; return; } // 找到匹配项,执行处理函数 (this->*(eit->second))(line); // << 是否存在不需要this->*的替代语法? } void aaa(const std::string& info) { std::cout << "执行aaa处理函数" << std::endl; } void bbb(const std::string& info) { std::cout << "执行bbb处理函数" << std::endl; } }; int main() { Example eg; eg.lookup("aaa"); // 正常执行 eg.lookup("bbb is legal"); // 正常执行 eg.lookup("bbbb is illegal"); // 失败:bbbb未定义 eg.lookup("cc"); // 失败:cc未定义 eg.lookup("aaaa"); // 失败:aaaa未定义 }
在lookup函数末尾,我通过(this->*(eit->second))(line);执行处理函数,想了解是否存在不使用this->*的替代调用语法。
可行的替代方案
1. 使用C++17的std::invoke
std::invoke是C++17引入的通用调用工具,可以统一处理普通函数、成员函数指针、函数对象等的调用逻辑,无需手动编写this->*语法。需要先包含<functional>头文件,调用方式如下:
std::invoke(eit->second, this, line);
它会自动完成成员函数指针与当前对象的绑定,代码更简洁易读。
2. 改用std::function存储绑定后的函数
如果允许修改lut的类型,可以将成员函数指针替换为绑定了当前对象的std::function,这样调用时完全不需要this->*:
#include <functional> // 需包含此头文件 class Example { public: // 修改map的存储类型为std::function std::map<std::string, std::function<void(const std::string&)>> lut; Example() { // 用lambda捕获当前对象,绑定成员函数 lut["aaa"] = [this](const std::string& info) { this->aaa(info); }; lut["bbb"] = [this](const std::string& info) { this->bbb(info); }; } void lookup(const std::string& line) { // ... 关键字查找逻辑保持不变 ... // 直接调用函数对象即可 eit->second(line); } // ... 成员函数aaa、bbb保持不变 ... };
这种方式的调用语法和普通函数完全一致,可读性更高,仅会带来可忽略的lambda额外开销。
3. 封装调用逻辑(避免重复写this->*)
可以写一个简单的辅助成员函数,封装成员函数指针的调用逻辑,减少重复代码:
class Example { // ... 其他成员 ... private: void callHandler(void (Example::*handler)(const std::string&), const std::string& arg) { (this->*handler)(arg); } };
然后在lookup中调用:
callHandler(eit->second, line);
这种方式本质还是依赖this->*,但可以避免在业务代码中重复书写该语法。
为什么必须绑定对象?
非静态成员函数的指针本身不包含对象实例信息,必须和具体对象(这里是this指向的当前实例)绑定才能确定调用上下文,因此绕开对象实例直接调用成员函数指针是不可能的。上述方案都是通过不同方式隐式处理了绑定逻辑,而非真正消除对象依赖。
内容的提问来源于stack exchange,提问作者cup
相关产品推荐
相关产品推荐

