Нужна помощь в решении полиморфизма во время выполнения с использованием шаблонов - PullRequest
1 голос
/ 28 марта 2012

В течение некоторого времени у меня был шаблон, который упаковывает библиотеку C FILE *. Это довольно классическая реализация общего указателя на класс-оболочку для ФАЙЛА *. Причина использования моего собственного общего указателя заключается в том, чтобы предоставить бесплатные замены функций для некоторых свободных функций FILE * из библиотеки C, чтобы я мог выполнить замену устаревшего кода, который работает с FILE *.

.

Реализация, которая у меня есть, использует внутреннюю оболочку, которая гарантирует, что при ее удалении собственный FILE * будет закрыт. RAII.

Однако я столкнулся с необходимостью создать аналогичную систему для обработки случая, когда я хочу, чтобы базовый ФАЙЛ * был сброшен и обрезан, а не закрыт, когда уничтожен последний держатель ФАЙЛА *. То есть у меня есть открытый файл FILE * исходного типа с гарантированным закрытием, но я хочу передать неизвестную копию файла FILE * другому объекту, который будет гарантировать, что при уничтожении его последнего экземпляра он будет сбрасывать и обрезать ФАЙЛ *, а не закрывать его, поэтому я оставлю базовый ФАЙЛ * в открытом состоянии, но с содержимым потока, сброшенным на диск (и размер файла, отражающий только допустимое содержимое).

Я решил это тривиально для полиморфизма времени компиляции. Но мне нужен какой-то способ для обеспечения полиморфизма во время выполнения, и я действительно не хочу помещать еще один слой косвенности в этот сценарий (то есть, если я использовал полиморфный указатель либо на автоматическое закрытие, либо на автоматическую очистку ФАЙЛА * обертка, я был бы золотым - но я действительно хочу сохранить ту же глубину, что и сейчас, и скрыть полиморфизм внутри реализации пользовательского общего указателя).

В основном, если у меня есть:

template <class WrapperT>  
class FilePointerT  
{  
public:
  // omitted: create, destroy, manipulate the underlying wrappered FILE*  
private:
  WrapperT * m_pFileWrapper;  
  ReferenceCount m_rc;  
}

Очевидно, тонны деталей опущены. Достаточно сказать, что когда последний из этих объектов удаляется, он удаляет последний m_pFileWrapper (фактически, если бы я переписывал этот код, я бы, вероятно, использовал boost :: shared_ptr).

Несмотря на это, реальная проблема здесь в том, что я нахожусь в тупике о том, как получить FilePointerT , чей WrapperT может варьироваться, но затем может использоваться в коде, как если бы они все были одинаковыми (что, в конце концов, они поскольку реализация WrapperT не имеет никакого влияния на структуру и интерфейс FilePointerT (по сути, pimpl).

Что я могу объявить, что может содержать любой FilePointerT для любого WrapperT?

Или, как я могу изменить определение FilePointerT, чтобы я мог указать конкретный WrapperT?

Ответы [ 3 ]

3 голосов
/ 28 марта 2012

Разве вы не можете просто использовать std::shared_ptr<FILE *, deleter_function>?Обеспечьте обычные перегрузки для бесплатных функций, никаких забавных шаблонов малярки.

2 голосов
/ 28 марта 2012

Вы можете использовать type erasure для прозрачной обработки всех версий FilePointerT. Как упоминалось в приведенном выше плакате, я бы также использовал подход shared_ptr, поскольку на самом деле средство удаления даже не является частью сигнатуры shared_ptr, поэтому вы сможете изменять средство удаления, сохраняя тип константным.

0 голосов
/ 10 октября 2012

Для чего я стою, в итоге я вставил обертку в класс FilePointer вместо того, чтобы сделать ее частью своего типа.

class FilePointer
{
public:
    // create using a file wrapper (which will handle policy issues)
    FilePointer(FileWrapper * pfw) : m_pFileWrapper(pfw) { }

protected:
    FileWrapper *   m_pFileWrapper; // wrapper has close/flush policy
    ReferenceCount  m_references;   // reference count
};

Затем указатель файла просто делегирует реальную работу оболочке, а оболочка реализует необходимую политику, и можно написать код для использования FilePointer (s).

Очевидно, есть и другие способы сделать это, но это то, с чем я пошел.

...