标准说
操作数应具有指针类型,或具有单个转换函数(12.3.2)到指针类型的类类型。如果操作数具有类类型,则通过调用上述转换函数将操作数转换为指针类型,并在本节的其余部分使用转换后的操作数代替原始操作数。
您可以 (ab) 通过声明转换函数的 const 版本来使用重载解析的缺失。在足以使它不再与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 指针类型。虽然实际的转换仍然经过类型检查,但这并不排除预先进行转换,而是在很久以后给出编译时错误。可悲的是,C++03 中的转换函数似乎无法使用 SFINAE :) 另一种方法是从另一个函数返回私有嵌套类型指针
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; }
};
请注意,这些变通方法仅适用于不符合要求的编译器。