调用shared_from_this()为何必须用this->?跨平台编译异常解析
在跨平台项目中,我有部分代码在Visual Studio编译正常,但调用shared_from_this()而非this->shared_from_this()时,GCC和Clang编译失败。
第一个最小示例代码
#include <memory> struct class1: public std::enable_shared_from_this<class1> { template<typename T> struct class2: public std::enable_shared_from_this<class2<T>> { void func() { this->shared_from_this(); // 此写法正常 shared_from_this(); // 此写法报错??? } }; }; void foo() { class1::class2<int>().func(); }
GCC编译报错
$ g++ -c bug.cpp bug.cpp: In instantiation of ‘void class1::class2<T>::func() [with T = int]’: bug.cpp:18:28: required from here bug.cpp:11:41: error: cannot call member function ‘std::shared_ptr<_Tp> std::enable_shared_from_this<_Tp>::shared_from_this() [with _Tp = class1]’ without object 11 | shared_from_this(); // this gives an error ??? | ~~~~~~~~~~~~~~~~^~
Clang编译报错
$ clang++ -c bug2.cpp bug.cpp:11:4: error: call to non-static member function without an object argument shared_from_this(); // this gives an error ??? ^~~~~~~~~~~~~~~~ bug.cpp:18:24: note: in instantiation of member function 'class1::class2<int>::func' requested here class1::class2<int>().func(); ^
移除外部类后的简化示例代码
#include <memory> template<typename T> struct class1: public std::enable_shared_from_this<class1<T>> { void func() { this->shared_from_this(); // 此写法正常 shared_from_this(); // 此写法报错??? } }; void foo() { class1<int>().func(); }
GCC编译报错
$ g++ -c bug1.cpp bug1.cpp: In member function ‘void class1<T>::func()’: bug1.cpp:9:17: error: there are no arguments to ‘shared_from_this’ that depend on a template parameter, so a declaration of ‘shared_from_this’ must be available [-fpermissive] 9 | shared_from_this(); // this gives an error ??? | ^~~~~~~~~~~~~~~~ bug1.cpp:9:17: note: (if you use ‘-fpermissive’, G++ will accept your code, but allowing the use of an undeclared name is deprecated)
Clang编译报错
$ clang++ -c bug1.cpp bug1.cpp:9:3: error: use of undeclared identifier 'shared_from_this' shared_from_this(); // this gives an error ???
问题
我的代码确实存在问题吗(若存在,原因是什么)?还是GCC和Clang存在常见bug?
解答
这不是编译器bug,你的代码确实不符合C++标准规定,核心原因是模板上下文的名字查找规则:
- 对于普通非模板类,编译器会自动在基类中查找未限定的成员名;但对于模板类(或嵌套在模板中的类),编译器不会自动去依赖基类(即基类类型依赖于模板参数,比如
std::enable_shared_from_this<class2<T>>)中查找未限定的成员名。 shared_from_this()是基类std::enable_shared_from_this的成员函数,直接写shared_from_this()时,在模板上下文中编译器无法确定这个名字来自依赖基类,会尝试在当前作用域或全局作用域查找,找不到就报错。- 而
this->shared_from_this()明确告知编译器:要从当前对象的基类中查找该成员,触发依赖于模板参数的名字查找,编译器会延迟到模板实例化时再去基类中查找,因此能正确定位到目标函数。
在第一个嵌套类示例中,GCC报错提到std::enable_shared_from_this<class1>,是因为编译器找不到目标成员时,会尝试去外部类class1的基类中查找,但该基类的shared_from_this属于class1,和当前class2<T>实例无关,因此报“无对象调用成员函数”的错误。
Visual Studio的编译器在名字查找规则上做了宽松实现,默认会在依赖基类中查找未限定成员名,因此能编译通过,但这并不符合标准规范。
内容的提问来源于stack exchange,提问作者Mario Klebsch
相关产品推荐
相关产品推荐

