成员箭头运算符由编译器以特殊方式处理。由于重载箭头运算符可以具有任意返回类型,因此可能需要将来自不同类的多个此类运算符“链接”在一起才能获得指针值。这个“链接”过程是由编译器在幕后自动完成的。重载类方法
T operator->() { ... }
可以像任何其他方法一样手动调用(例如。
return obj.operator->();
),但这只会产生类型的结果
T
。我想知道是否有一些特定的方法可以手动调用这个重载
operator->()
该方法将导致获取底层“链式”指针值,而不是任意结果类型
T
.
下面的例子有3种不同的方法来获取我想到的底层“链式”指针值,但似乎都没有解决这个问题:
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->() {
// Trying to access the underlying int* pointer
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 x
成员就像一种方法。对于
D<A>
专业化是可行的,但两者都
D<B>
和
D<C>
由于调用的结果,将导致编译错误
操作员->()
将
B
和
C
分别不可转换为
int*
.
2.
使用解引用运算符和
std::addressof
在上面的例子中,这种方法不起作用,因为没有一个类
operator*()
定义为编译器抛出错误。即使定义了解栅栏运算符(例如迭代器类)
D
类模板应该充当以下对象的代理
A
,
B
和
C
类类型,因此实现
D<T>::operator->()
应明确使用依赖项
T::operator->()
The
T::operator*()
和
std::addressof
组合似乎是一种“变通方法”,如果包装好,甚至可能无法正常工作
T: :操作员->()
有一些奇怪的副作用
T: :操作员*()
没有。
3.
根据需要手动键入尽可能多的成员箭头运算符。这基本上就是编译器在幕后所做的。这种方法显然非常脆弱,只适用于
D<C>
专业化。
对于上下文,我目前正在实现一个类型擦除的视图/范围类,该类可以从任何可以迭代的容器中构造。为了实现目的,我还为类型擦除迭代器定义了一个类,该类充当底层集合迭代器的代理。这个
struct D
在上面的示例中,表示该类型的擦除迭代器类,而
C c
成员表示特定/底层迭代器数据(例如std::vector迭代器、某种std::ranges::view迭代器等)。由于类型擦除,返回类型为
D::operator->()
不能与返回的相同
C::operator->()
因为这种类型也必须被擦除。