非类型形参取决于它后面的实参



我正在编写一个封装win32处理RAII的模板化类。这是我目前得到的:

#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();
}

对于接受一个HANDLE参数并释放它的API来说是很好的。现在,我的问题是API需要多个参数来释放句柄,如

ReleaseDC(HWND, HDC);
SelectObject(HDC, HGDIOBJ);

在deleter函数有多个参数的情况下,我愿意实现的客户端使用语法是:

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依赖于它后面的实参,这是非法的。因此:困…

Thanks in advance

注:对于更好的标题,更好的用法语法等等,欢迎提出任何想法

这是它如何工作的(使用c++ 1y的make_index_sequence)。不确定您使用该引用参数的设计,但是

template<typename Signature, std::function<Signature> &Deleter>
class Win32Raii;
template<typename ...Types, std::function<void(Types...)> &Deleter>
class Win32Raii<void(Types...), Deleter> { 
public:
   ~Win32Raii() {
      // do as proposed in http://stackoverflow.com/a/7858971/34509
      callDelete(std::make_index_sequence<sizeof...(Types)>{});
   }
private:
   template<std::size_t ...I>
   void callDelete(std::integer_sequence<std::size_t, I...>) {
       Deleter(std::get<I>(args)...);
   }
   std::tuple<Types...> args;
};

我是这样修改的

template<typename Deleter, typename ...Params>
class Win32Raii {
public:
   Win32Raii(Params... args, Deleter deleter = Deleter());
   ~Win32Raii() { /* copy most from above ... */ }
private:
   Deleter deleter;
   std::tuple<Params...> args;
};

这与间接层

完全兼容
template<typename Type, Type &Deleter>
struct ExoticDeleter {
   template<typename ...T>
   void operator()(T&&...t) const (
      Deleter(std::forward<T>(t)...);
   }
};
typedef Win32Raii< 
   ExoticDeleter<decltype(destroy_icon), destroy_icon>,
   HICON
> HiconRaii;

我颠倒了顺序,这样多个参数就可以作为一个简单的序列给出,而不需要包装它们。但这只是个人喜好。

最新更新