C++ 为什么箭头 (->) 运算符的自动重新应用不适用于指针到指针类型?
C++ Why does the automatic re-application of the arrow (->) operator not apply to pointer-to-pointer types?
This question 讨论箭头运算符 ->
如何自动重新应用于重载 operator->()
的 return 值,直到值 returned是原始指针,此时原始指针被取消引用,就好像使用 ->
一样。但是,当他们希望取消对基值的引用时,情况就不一样了——他们必须使用 (*ptr_to_ptr)->foo()
来代替。在我看来,ptr_to_ptr->foo()
的用法是明确的,甚至比 ->
自动重新应用到 returned 值直到原始指针被 returned 更是如此.那么,这个决定背后的原因是什么?
最小工作示例:
#include <iostream>
struct Dog {
void bark() { std::cout << "woof!" << std::endl; }
};
struct DogWalker {
Dog* dog;
Dog* operator->() {
return dog;
}
};
struct DogOwner {
DogWalker walker = { new Dog() };
DogWalker operator->() {
return walker;
}
};
void main()
{
DogOwner owner;
owner->bark(); // works, prints "woof"
Dog** ptr_to_ptr = new Dog*;
*ptr_to_ptr = new Dog;
(**ptr_to_ptr).bark(); // works
(*ptr_to_ptr)->bark(); // works
//ptr_to_ptr->bark(); // ERROR
//C2227: left of '->bark' must point to class/struct/union/generic type
}
该语言采用了 C 的大部分语义。应用于指针类型的 ->
运算符仅在指针指向 non-array 复合类型时才有效。由于 C 没有 classes,C++ 为重载 ->
定义了自己的语义,这对智能指针用例有意义。
您可以使用助手实现您想要的行为 class。
template <typename T>
struct Unwrap {
T *p_;
Unwrap (T *p = 0) : p_(p) {}
T * operator -> () const { return p_; }
};
template <typename T>
struct Unwrap<T *> {
T **p_;
Unwrap (T **p = 0) : p_(p) {}
Unwrap<T> operator -> () const { return *p_; }
};
template <typename T>
Unwrap<T> make_unwrap (T *p) { return p; }
然后你可以像这样使用它:
struct foo {
void bar () { std::cout << "Hello\n"; }
};
int main () {
foo p;
auto pp = &p;
auto ppp = &pp;
auto pppp = make_unwrap(&ppp);
pppp->bar();
}
This question 讨论箭头运算符 ->
如何自动重新应用于重载 operator->()
的 return 值,直到值 returned是原始指针,此时原始指针被取消引用,就好像使用 ->
一样。但是,当他们希望取消对基值的引用时,情况就不一样了——他们必须使用 (*ptr_to_ptr)->foo()
来代替。在我看来,ptr_to_ptr->foo()
的用法是明确的,甚至比 ->
自动重新应用到 returned 值直到原始指针被 returned 更是如此.那么,这个决定背后的原因是什么?
最小工作示例:
#include <iostream>
struct Dog {
void bark() { std::cout << "woof!" << std::endl; }
};
struct DogWalker {
Dog* dog;
Dog* operator->() {
return dog;
}
};
struct DogOwner {
DogWalker walker = { new Dog() };
DogWalker operator->() {
return walker;
}
};
void main()
{
DogOwner owner;
owner->bark(); // works, prints "woof"
Dog** ptr_to_ptr = new Dog*;
*ptr_to_ptr = new Dog;
(**ptr_to_ptr).bark(); // works
(*ptr_to_ptr)->bark(); // works
//ptr_to_ptr->bark(); // ERROR
//C2227: left of '->bark' must point to class/struct/union/generic type
}
该语言采用了 C 的大部分语义。应用于指针类型的 ->
运算符仅在指针指向 non-array 复合类型时才有效。由于 C 没有 classes,C++ 为重载 ->
定义了自己的语义,这对智能指针用例有意义。
您可以使用助手实现您想要的行为 class。
template <typename T>
struct Unwrap {
T *p_;
Unwrap (T *p = 0) : p_(p) {}
T * operator -> () const { return p_; }
};
template <typename T>
struct Unwrap<T *> {
T **p_;
Unwrap (T **p = 0) : p_(p) {}
Unwrap<T> operator -> () const { return *p_; }
};
template <typename T>
Unwrap<T> make_unwrap (T *p) { return p; }
然后你可以像这样使用它:
struct foo {
void bar () { std::cout << "Hello\n"; }
};
int main () {
foo p;
auto pp = &p;
auto ppp = &pp;
auto pppp = make_unwrap(&ppp);
pppp->bar();
}