Я пишу шаблонный класс, который инкапсулирует RAII-обработчики win32. Это то, что у меня есть до сих пор:
#define NOMINMAX
#include <Windows.h>
#include <functional>
// problem: optionally pass additional params to the deleter function
template<typename ResourceT, std::function<void(ResourceT)> &Deleter>
class Win32Raii
{
Win32Raii(const Win32Raii &);
Win32Raii &operator=(const Win32Raii &);
public:
Win32Raii()
: m_resource(nullptr)
{}
Win32Raii(const ResourceT &r)
: m_resource(r)
{}
Win32Raii(Win32Raii &&other)
: m_resource(nullptr)
{
*this = std::move(other);
}
~Win32Raii()
{
if (m_resource)
{
Deleter(m_resource);
}
}
Win32Raii &operator=(Win32Raii &&other)
{
std::swap(m_resource, other.m_resource);
return *this;
}
ResourceT get() const { return m_resource; }
private:
ResourceT m_resource;
};
// library code for each resource type
std::function<void(HICON)>destroy_icon = [](HICON h){ ::DestroyIcon(h); };
std::function<void(HDC) > delete_dc = [](HDC h){ ::DeleteDC(h); };
//problem: pass real HWND first arg, not just a nullptr constant
std::function<void(HDC) > release_dc = [](HDC dc) { ::ReleaseDC(nullptr, dc); };
typedef Win32Raii<HICON, destroy_icon> HiconRaii;
typedef Win32Raii<HDC, delete_dc > HdcDelRaii;
typedef Win32Raii<HDC, release_dc > HdcRelRaii;
typedef Win32Raii<HMENU, destroy_menu> HmenuRaii;
//client usage examples
void main()
{
HWND hWnd = ::FindWindowA(nullptr, "some window");
// problem: pass hWnd
HdcRelRaii rdc(::GetDC(hWnd) /*, hWnd */);
HdcDelRaii ddc(::CreateCompatibleDC(rdc.get()));
HiconRaii h;
HiconRaii h2(::LoadIconW(nullptr, IDI_APPLICATION));
h = HiconRaii(std::move(h2));
HiconRaii h3 = std::move(h);
h3 = HiconRaii();
}
Это хорошо для API, которые принимают один аргумент HANDLE и освобождают его. Теперь моя проблема заключается в API, которые принимают несколько аргументов для выпуска дескриптора, например
ReleaseDC(HWND, HDC);
SelectObject(HDC, HGDIOBJ);
Синтаксис использования клиента, которого я хочу достичь в случае нескольких параметров функции удаления:
HdcRelRaii dc_to_release_in_dtor(::GetDC(hWnd), hWnd);
SelectObjRaii obj_to_reselect_in_dtor(::SelectObject(hBrush, hDC), hDC);
Итак, наконец, вопрос: как я могу изменить
template<typename ResourceT, std::function<void(ResourceT)> &Deleter>
к чему-то вариативному, например
template<
typename ResourceT,
std::function<void(ResourceT, Args&...) &Deleter,
typename... Args>
>
?
Очевидно, что параметр Deleter, не являющийся типом, зависит от аргументов, которые идут после него, что недопустимо. Отсюда: застрял...
заранее спасибо
P.S. приветствуются любые идеи по лучшему заголовку, лучшему синтаксису использования и т.д.
shared_ptr
? - person Yakk - Adam Nevraumont   schedule 17.03.2014Deleter
параметром шаблона типа и создать объект-член типаDeleter
в своем конструкторе, а затем вызвать его. Вот как, например,std::set
сравнивает объекты - person Brian Bi   schedule 17.03.2014Deleter
и инициализировать его в конструкторе. - person stardust   schedule 17.03.2014template<typename Signature, std::function<Signature> &Deleter>
и адаптировать синтаксис клиента кWin32Raii<void(HICON, HDC), destroy_icon_with_hdc>
? - person Johannes Schaub - litb   schedule 17.03.2014shared_ptr
не требуется передавать конструкторам удаляющие элементы: только если они имеют зависимости для каждого экземпляра. Если по умолчанию один из типов выполняет задание, например. - person Yakk - Adam Nevraumont   schedule 17.03.2014DeleterType<destroy_icon>
в качестве типа удаления, чейoperator()
просто будет делать то, что вы сейчас делаете напрямую. - person Johannes Schaub - litb   schedule 17.03.2014