我正在尝试创建一个模板,其中默认值可以作为非类型参数传递。
原始类型(WINAPI的HANDLE
)是从编译器角度来看的指针类型,但从用户的角度来看则被视为整数类型。
// Somewhere in system headers
#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)
typedef void *HANDLE;
// My code
template<typename Handle, Handle Default>
class HandleWrapper
{
...
};
HandleWrapper<HANDLE, INVALID_HANDLE_VALUE>; // error: invalid nontype template argument of type `HANDLE`
我目前的解决方法:
template<typename Handle, uintptr_t Default>
class HandleWrapper
{
static_assert(std::is_pointer<Handle>::value, "Handle must be a pointer");
static constexpr Handle DefaultHandle = reinterpret_cast<Handle>(Invalid);
};
我想正确的解决方案是以某种方式指定typename Handle
应该被视为整数类型(uintptr_t
),只要会话没有缩小。
答案 0 :(得分:1)
在我的代码中,我使用了一个模板化的句柄包装类,但是我采用了与你不同的方法。我为每个要包装的句柄类型定义了一个单独的traits
类,然后使用template参数指定要在包装器中使用的特征。
尝试在您的情况下做类似的事情,例如:
struct InvalidHandleTraits
{
using HandleType = HANDLE;
static constexpr HANDLE DefaultHandle = INVALID_HANDLE_VALUE;
//...
static void Close(HANDLE h) { CloseHandle(h); }
//...
};
struct NullHandleTraits
{
using HandleType = HANDLE;
static constexpr HANDLE DefaultHandle = NULL;
//...
static void Close(HANDLE h) { CloseHandle(h); }
//...
};
... other traits as needed...
template<typename traits = InvalidHandleTraits>
class HandleWrapper
{
public:
using HandleType = typename traits::HandleType;
HandleWrapper(HandleType h = traits::DefaultHandle) : m_handle(h) { std::cout << "constructor: " << h << std::endl; }
~HandleWrapper() { traits::Close(m_handle); }
//...
operator HandleType() { return m_handle; }
private:
HandleType m_handle;
};
然后,您可以在需要时使用所需的traits
课程,例如:
HandleWrapper<> h = CreateFile(...);
// or:
// HandleWrapper<InvalidHandleTraits> h = CreateFile(...);
HandleWrapper<NullHandleTraits> h = CreateFileMapping(...);