为何无法通过点运算符直接引用未调用的非静态成员函数?
为什么无法直接通过
auto member_func = foo.do_something;获取绑定对象的非静态成员函数? #include <iostream> #include <functional> class Foo { private: int m_num; char m_letter; public: explicit Foo(int a, char c) : m_num(a), m_letter(c) {} int const& num() const { return m_num; } char const& letter() const { return m_letter; } void do_something(void) { std::cout << m_num << ", " << m_letter << "\n"; } }; int main(void) { Foo foo(7, 'z'); // 无法编译 // std::function<void(void)> member_func1 = foo.do_something; std::function<void(void)> member_func2 = [&foo]() -> auto { foo.do_something(); }; std::function<void(Foo&)> member_func3 = std::mem_fn(&Foo::do_something); }
尝试编译被注释的代码行时,会得到错误:reference to non-static member function must be called,提示非静态成员函数必须被调用。目前可以通过lambda包装(绑定对象)或std::mem_fn(生成需传对象的函数器)两种方式解决,但希望能直接用auto member_func = foo.do_something;这种简洁写法,以下是相关原因和标准限制的解释:
核心原因:C++语言的明确性设计与歧义避免
- 非静态成员函数的本质:所有非静态成员函数都隐含一个
this指针参数,调用时必须绑定到某个类对象。foo.do_something这种写法在C++语法中,默认被解释为调用该成员函数(即需要加()执行),而非获取一个绑定了foo的可调用对象。如果允许省略()直接获取绑定函数,会和"调用函数"的语法产生歧义。 - 意图的二义性:编译器无法从
auto member_func = foo.do_something;这句话中判断你的真实意图:- 是想生成一个绑定了
foo的闭包(不需要再传对象,直接调用member_func()即可); - 还是想获取成员函数的指针(后续需要传对象调用,比如
member_func(foo))。
这两种情况的类型完全不同,C++作为静态类型语言,要求必须明确表达意图,不能依赖编译器猜测。
- 是想生成一个绑定了
C++标准中的相关限制
C++标准规定,非静态成员函数的名字不能直接作为表达式生成可调用对象:
- 若要获取成员函数指针,必须使用取地址操作符:
&Foo::do_something,得到的类型是void(Foo::*)(); - 若要生成绑定对象的可调用对象,必须显式通过lambda、
std::bind或std::mem_fn等工具实现,这些工具会明确捕获对象或要求传入对象,消除二义性。
实现层面的可行性
从技术上看,编译器完全有能力实现auto member_func = foo.do_something;这种语法(比如默认生成绑定对象的闭包),但C++标准委员会选择不支持这种写法,核心原因是语言设计的保守性和明确性原则:避免隐式行为带来的意外,让程序员的代码意图清晰可见。如果允许隐式绑定,可能会导致开发者意外捕获对象的引用/值,引发生命周期问题(比如lambda捕获引用时对象提前销毁),而显式写法能强制开发者考虑这些细节。
内容的提问来源于stack exchange,提问作者zebra14420
相关产品推荐
相关产品推荐

