标准说
操作数应具有指针类型,或具有到指针类型的单个转换函数(12.3.2)的类类型。如果操作数是类类型,则通过调用上述转换函数将操作数转换为指针类型,并在本节的其余部分中使用转换后的操作数代替原始操作数。
您可以通过声明转换函数的 const 版本来 (ab) 使用缺少重载解析的情况。在一个合格的编译器上,这足以使它不再工作delete
:
struct A {
operator int*() { return 0; }
operator int*() const { return 0; }
};
int main() {
A a;
int *p = a; // works
delete a; // doesn't work
}
结果如下
[js@HOST2 cpp]$ clang++ main1.cpp
main1.cpp:9:3: error: ambiguous conversion of delete expression of type 'A' to a pointer
delete a; // doesn't work
^ ~
main1.cpp:2:3: note: candidate function
operator int*() { return 0; }
^
main1.cpp:3:3: note: candidate function
operator int*() const { return 0; }
^
1 error generated.
在这方面不太符合要求的编译器(EDG/Comeau、GCC)上,您可以将转换函数设为模板。delete
不期望特别的类型,这样就可以工作:
template<typename T>
operator T*() { return /* ... */ }
但是,这有一个缺点,您的智能指针现在可以转换为any指针类型。尽管实际的转换仍然经过类型检查,但这不会预先排除转换,而是会在稍后给出编译时错误。遗憾的是,SFINAE 似乎无法使用 C++03 中的转换函数:) 另一种方法是从其他函数返回私有嵌套类型指针
struct A {
operator int*() { return 0; }
private:
struct nested { };
operator nested*() { return 0; }
};
现在唯一的问题是转换为void*
,在这种情况下,两个转换函数同样可行。 @Luther 建议的解决方法是从另一个转换函数返回函数指针类型,该函数适用于 GCC 和 Comeau,并摆脱了void*
与模板解决方案不同,在通常的转换路径上没有其他问题
struct A {
operator int*() { return 0; }
private:
typedef void fty();
operator fty*() { return 0; }
};
但请注意,只有不符合标准的编译器才需要这些解决方法。