Моя ситуация следующая:
У меня есть шаблонная оболочка, которая обрабатывает ситуацию значений и обнуляемых объектов без необходимости вручную обрабатывать указатель или даже new
. Это в основном сводится к этому:
struct null_t
{
// just a dummy
};
static const null_t null;
template<class T> class nullable
{
public:
nullable()
: _t(new T())
{}
nullable(const nullable<T>& source)
: _t(source == null ? 0 : new T(*source._t))
{}
nullable(const null_t& null)
: _t(0)
{}
nullable(const T& t)
: _t(new T(t))
{}
~nullable()
{
delete _t;
}
/* comparison and assignment operators */
const T& operator*() const
{
assert(_t != 0);
return *_t;
}
operator T&()
{
assert(_t != 0);
return *_t;
}
operator const T&() const
{
assert(_t != 0);
return *_t;
}
private:
T* _t;
};
Теперь, используя операторы сравнения, я могу проверить фиктивный код null_t
, чтобы увидеть, установлено ли для него значение null, прежде чем пытаться получить значение или передать его в функцию, которая требует это значение и выполняет автоматическое преобразование. .
Этот урок довольно долго служил мне, пока я не наткнулся на проблему. У меня есть класс данных, содержащий некоторые структуры, которые все будут выводиться в файл (в данном случае XML).
Так что у меня есть такие функции
xml_iterator Add(xml_iterator parent, const char* name,
const MyDataStruct1& value);
xml_iterator Add(xml_iterator parent, const char* name,
const MyDataStruct2& value);
каждый из которых заполняет XML-DOM соответствующими данными. Это также работает правильно.
Теперь, однако, некоторые из этих структур являются необязательными, которые в коде будут объявлены как
nullable<MyDataStruct3> SomeOptionalData;
И для этого случая я сделал перегрузку шаблона:
template<class T>
xml_iterator Add(xml_iterator parent, const char* name,
const nullable<T>& value)
{
if (value != null) return Add(parent, name, *value);
else return parent;
}
В моих модульных тестах компилятор, как и ожидалось, всегда предпочитал выбирать эту функцию шаблона, где бы значение или структура не были заключены в nullable<T>
.
Если, однако, я использую вышеупомянутый класс данных (который экспортируется в свою собственную DLL), по какой-то причине самый первый раз, когда должна вызываться последняя функция шаблона, вместо этого происходит автоматическое преобразование из nullable<T>
в соответствующий тип T
сделано, полностью обходя функцию, предназначенную для обработки этого случая. Как я уже говорил выше - все модульные тесты прошли на 100% нормально, MSVC 2005 в режиме отладки собирает как тесты, так и исполняемый файл, вызывающий код, - эту проблему определенно нельзя отнести к различиям компилятора.
Обновление: уточнить - перегруженные функции Add
не экспортируются и используются только внутри DLL. Другими словами, внешняя программа, которая сталкивается с этой проблемой, даже не включает заголовок с перегруженной функцией шаблона.