是否可以将指针视为非类型模板参数中的整数类型?

时间:2018-03-02 23:40:03

标签: c++ templates

我正在尝试创建一个模板,其中默认值可以作为非类型参数传递。

原始类型(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),只要会话没有缩小。

1 个答案:

答案 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(...);

Live Demo