如何手动递归调用重载的operator->以获取底层链式指针?
如何手动触发operator->的链式调用以获取底层指针?
编译器会以特殊逻辑处理成员箭头运算符operator->:如果重载的operator->返回的不是原始指针,编译器会自动链式调用该返回值的operator->,直到得到一个原始指针为止。但手动调用obj.operator->()只能拿到该运算符直接返回的类型,而非最终的底层指针。我想知道有没有办法手动模拟编译器的这个链式调用过程,直接获取最终的底层指针值。
我尝试过三种方法,但都无法解决通用场景的问题:
#include <memory> // 用于std::addressof struct A { int data; int* operator->() { return std::addressof(this->data); } }; struct B { A operator->() { return A(); } }; struct C { B operator->() { return B(); } }; template <typename T> struct D { T x; int* operator->() { // 尝试获取底层int*指针的三种方式 // return this->x.operator->(); // (1) // return std::addressof(*this->x); // (2) // return this->x.operator->().operator->().operator->(); // (3) } }; int main() { D<A> da; D<B> db; D<C> dc; }
三种尝试方法的问题分析
- (1) 直接调用
T::operator->():仅对D<A>有效,因为A::operator->()直接返回int*。但对于D<B>和D<C>,调用结果分别是B和C类型,无法直接转换为int*,编译失败。 - (2) 结合解引用和
std::addressof:示例中因为A/B/C都没定义operator*(),编译器会报错。就算定义了该运算符,这种方式属于临时 workaround,而且如果被包装的T::operator->()有特殊副作用,但T::operator*()没有,就会导致逻辑不一致,不符合D作为代理需依赖T::operator->()的设计需求。 - (3) 手动硬编码链式调用:这本质上是编译器自动执行的逻辑,但只能适配固定层数的链式调用,比如仅对
D<C>有效,完全不具备通用性,改动底层类型就会失效。
背景
我正在实现一个可从任意可迭代容器构造的类型擦除视图/范围类,配套了一个类型擦除迭代器类(即示例中的D),作为底层集合迭代器的代理。C代表具体的底层迭代器(比如std::vector迭代器、std::ranges::view迭代器等)。由于类型擦除的要求,D::operator->()的返回类型不能与被包装迭代器的C::operator->()返回类型一致,否则该返回类型也需要被擦除,因此必须拿到最终的原始指针类型。
内容的提问来源于stack exchange,提问作者Die4Toast
相关产品推荐
相关产品推荐

