Стандарт гласит:
Операнд должен иметь тип указателя или тип класса, имеющий одну функцию преобразования (12.3.2) в тип указателя.Если операнд имеет тип класса, операнд преобразуется в тип указателя путем вызова вышеупомянутой функции преобразования, и преобразованный операнд используется вместо исходного операнда в оставшейся части этого раздела.
Вы можете (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 /* ... */ }
Однако у этого недостатка есть то, что ваш smartpointer теперь может быть конвертирован в любой указатель типа.Хотя фактическое преобразование все еще проверяется на типизацию, но это не исключает предварительные преобразования, а скорее приводит к ошибке времени компиляции намного позже.К сожалению, 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; }
};
Обратите внимание, что эти обходные пути необходимы только для не соответствующих требованиям компиляторов.