`this->tree_type`写法是否符合C++标准及相关技术疑问
我在扩展Boost.Intrusive库的项目中,treap_impl类里有这段代码:
node_ptr this_head(this->tree_type::header_ptr()); node_ptr right(this->tree_type::node_algorithms::root_node(this_head));
这段代码能在MSVC 17.9下编译通过,但在Clang或GCC中第二行会报错:
...::node_algorithms is not a base of treap_impl<...>
删掉第二行的this->就能解决编译错误,我有三个疑问:
- 这段代码(尤其是
this->tree_type部分)是否符合C++标准? - C++标准中哪部分内容与此相关?
- 是否存在我忽略的基础C++知识点?
以下是能在GCC和Clang中复现错误的示例代码(在Compiler Explorer的MSVC中也编译失败):
struct static_thing { static int value() { return 5; } }; struct A { using the_type = static_thing; }; class B { using a_type = A; void do_stuff() { int a(this->a_type::the_type::value()); } };
对应的报错信息:
error: ‘A::the_type’ {aka ‘static_thing’} is not a base of ‘B’
1. 这段代码不符合C++标准
this->tree_type::node_algorithms::root_node这种写法是错误的。this->的作用是触发依赖名称查找,但它只能用于访问当前类(或基类)的成员,包括类型别名。当你写this->a_type::the_type时,编译器会把a_type::the_type当成this指向对象的基类类型,而非单纯的嵌套类型别名引用——但static_thing并不是B的基类,所以报错。
第一行this->tree_type::header_ptr()能在MSVC编译,是因为MSVC做了非标准扩展(对依赖名称查找的宽松处理),标准C++里这种写法其实也不规范,只是部分编译器没严格检查。正确写法是去掉this->,直接写tree_type::header_ptr()和tree_type::node_algorithms::root_node(this_head)。
2. 相关的C++标准内容
核心是依赖名称的查找规则和类成员访问的语法:
- 在类模板的成员函数中,
this->用于标记某个名称是依赖于模板参数的成员(即依赖名称),编译器会延迟查找该名称直到模板实例化时。但this->X::Y的写法,标准要求X必须是当前类(或其基类)的类型成员,且Y是X的成员;而这里的X::Y是嵌套类型时,this->会让编译器误以为X::Y是当前类的基类,而非单纯的类型引用。 - C++标准的[expr.ref]章节(类成员访问表达式)明确:
E1->E2形式中,E2必须是E1指向对象的成员(包括继承来的成员)。当E2是X::Y这种嵌套名称时,X必须是E1类型的基类,或者X是E1类型的成员类型,但this->X::Y的写法会被解析为“访问this对象的基类X::Y的成员”,而非“访问X类型中的Y成员”。
3. 容易忽略的基础知识点
this->的正确使用场景:this->主要用于类模板中区分依赖名称和非依赖名称,比如模板基类的成员被隐藏时,用this->访问基类的依赖成员。但它不能直接引用嵌套的类型别名链,比如this->A::B::C这种写法是错误的,因为A::B不是当前类的基类。- 类型别名的访问方式:访问类中的类型别名,直接用
类型别名::嵌套成员即可,不需要加this->——除非这个类型别名本身是依赖于模板参数的基类成员,但即使是这种情况,也要确保this->后面的是基类,而非嵌套类型。 - 编译器的非标准扩展:MSVC有时会对不符合标准的写法做兼容处理,导致代码在MSVC能编译,但在标准兼容的编译器(如GCC、Clang)下报错,这种情况要以标准为准,避免依赖编译器扩展。
内容的提问来源于stack exchange,提问作者laralaralara

