Я недавно прочитал статью safe bool . Я видел, как эта техника использовалась несколько раз, но никогда не понимал, почему она работает, или именно поэтому она была необходима (вероятно, как и многие, я понял ее суть: просто с помощью operator bool () const позволили некоторые неявные преобразования типа shenanigans, но детали были для меня всегда немного туманными).
Прочитав эту статью, а затем рассмотрев некоторые из ее реализаций в Boost shared_ptr.hpp, я подумал, что справился с этим. Но когда я решил реализовать его для некоторых классов, которые мы заимствовали и расширили или разработали с течением времени, чтобы помочь управлять работой с API-интерфейсами Windows, я обнаружил, что моя наивная реализация не работает должным образом (исходный код компилируется, но использование генерирует ошибка во время компиляции, не найдены правильные преобразования).
Реализации Boost изобилуют условиями для различных уровней поддержки C ++ компиляторами. От использования наивного оператора bool () const до использования указателя на функцию-член и использования указателя на данные-член. Из того, что я понял, указатель на данные члена является наиболее эффективным для компиляторов, если они обрабатывают IFF, когда они вообще его обрабатывают.
Я использую MS VS 2008 (MSVC ++ 9). И ниже пара реализаций, которые я пробовал. Каждое из них приводит к Неоднозначное пользовательское преобразование или оператор не найден .
template<typename HandlePolicy>
class AutoHandleTemplate
{
public :
typedef typename HandlePolicy::handle_t handle_t;
typedef AutoHandleTemplate<HandlePolicy> this_type;
{details omitted}
handle_t get() const { return m_handle; }
operator handle_t () const { return m_handle; }
#if defined(NAIVE)
// The naive implementation does compile (and run) successfully
operator bool () const { return m_handle != HandlePolicy::InvalidHandleValue(); }
bool operator ! () const { return m_handle == HandlePolicy::InvalidHandleValue(); }
#elif defined(FUNC_PTR)
// handle intrinsic conversion to testable bool using unspecified_bool technique
typedef handle_t (this_type::*unspecified_bool_type)() const;
operator unspecified_bool_type() const // never throws
{
return m_handle != HandlePolicy::InvalidHandleValue() ? &this_type::get() : NULL;
}
#elif defined(DATA_PTR)
typedef handle_t this_type::*unspecified_bool_type;
operator unspecified_bool_type() const // never throws
{
return m_handle != HandlePolicy::InvalidHandleValue() ? &this_type::m_handle : NULL;
}
#endif
private :
handle_t m_handle;
{details omitted}
};
А вот фрагмент кода, который либо работает (наивная реализация), либо ошибки (любой из методов unspecified_bool, выше):
// hModule is an AutoHandleTemplate<ModuleHandlePolicy>
if (!hModule)
и
if (hModule)
Я уже пытался включить оператора! во всех случаях - но хотя первый случай тогда работает, второй не компилируется (неоднозначно).
Мне кажется, что этот класс очень похож на smart_ptr (или auto_ptr). В этом случае он должен поддерживать неявное преобразование в свой базовый тип дескриптора (HMODULE), но он также должен обрабатывать if (instance) и if (! Instance) . Но если я определяю и оператор handle_t, и метод unspecified_bool, я получаю ошибки.
Может кто-нибудь объяснить мне, почему это так, и, возможно, предложить лучший подход? (или я должен довольствоваться наивным подходом, по крайней мере, пока C ++ 0x не будет завершен и явные операторы не будут реализованы в моем компиляторе)?
EDIT:
Может показаться, что ответ вполне может состоять в том, что если я определю неявное преобразование в интеграл, то C ++ будет использовать это преобразование для любых выражений типа if (instance). И что, по крайней мере для вышеприведенного класса, единственная причина для определения любых других операторов (оператор bool) состоит в том, чтобы явно переопределить, используя неявное интегральное преобразование во что-то другое (в вышеприведенном случае, заставляя его сравнивать с INVALID_HANDLE_VALUE вместо неявный NULL).
А использование метода unspecified_bool действительно имеет смысл, только если вы не предоставляете интегральный оператор преобразования?