如何将模板 class 限制为仅具有类型别名的特定专业化
How to restrict template class to only specific specializations with type aliases
我的目标是拥有一个带有各种别名的模板化包装器 class。这是一个简化的预览:
template < typename Type >
class Wrapper {
public:
Wrapper(Type* resource) : ptr(resource) {}
~Wrapper() { free(ptr); }
private:
Type* ptr;
}
void free(SDL_Window* ptr) { SDL_DestroyWindow(ptr); }
void free(SDL_Renderer* ptr) { SDL_DestroyRenderer(ptr); }
using Window = Wrapper<SDL_Window>;
using Renderer = Wrapper<SDL_Renderer>;
我想只允许创建 Wrapper class 的这些别名实例。原因之一是,这是对 SDL 资源指针的包装,它根据指针的类型具有不同的内存释放功能。
我想实现的最佳方案是使 Wrapper class 在我创建的别名的使用之外不可见。也许有一个使用匿名命名空间的解决方案,但解冻意味着包装器 class 不能在头文件中。
std::enable_if
怎么样,它将只为您的 classes/functions 启用某些类型?
看看 C++11 和 14 中的 type_traits。您可以进行各种静态检查(编译时检查)。例如,要检查类型是否符合您的预期,您可以使用:
std::is_same<T,int>::value
如果 T
是 int
,这将 return 在编译时 为真 。
我认为这会有所帮助
template <typename T, bool Allowed>
class WrapperBase;
template <typename T>
class WrapperBase<T, true>
{
};
template <typename T>
class WrapperBase<T, false>;
template < typename Type >
class WrapperBaseHelper : public WrapperBase<T, boost::is_base_of<SDL_Window, T>::value | boost::is_base_of<SDL_Renderer>::value ...e.t.c >
{
...
};
Best scenario I would like to achieve would be to make Wrapper class not visible outside the usage of aliases I create.
这可以使用 private
和包装器 class
class WrapperAccessor {
template < typename Type >
class Wrapper {
public:
Wrapper(Type* resource) : ptr(resource) {}
~Wrapper() { free(ptr); }
private:
Type* ptr;
};
public:
using Window = Wrapper<SDL_Window>;
using Renderer = Wrapper<SDL_Renderer>;
};
using Window = WrapperAccessor::Window;
using Renderer = WrapperAccessor::Renderer;
在你的具体情况下,我会使用 std::unique_ptr
,类似于:
template <typename T, T value> struct Call; // c++17 should allow Call<auto F>
template <typename T, void (*f)(T*)>
struct Call<void (*)(T*), f>
{
void operator ()(T* p) const { f(p); }
};
#define AUTO(F) decltype(F), F // not needed in C++17
using Window = std::unique_ptr<SDL_Window, Call<AUTO(&SDL_DestroyWindow)>>;
using Renderer = std::unique_ptr<SDL_Renderer, Call<AUTO(&SDL_DestroyRenderer)>>;
处理已删除的副本并更正与您的代码段相反的移动语义。
我的目标是拥有一个带有各种别名的模板化包装器 class。这是一个简化的预览:
template < typename Type >
class Wrapper {
public:
Wrapper(Type* resource) : ptr(resource) {}
~Wrapper() { free(ptr); }
private:
Type* ptr;
}
void free(SDL_Window* ptr) { SDL_DestroyWindow(ptr); }
void free(SDL_Renderer* ptr) { SDL_DestroyRenderer(ptr); }
using Window = Wrapper<SDL_Window>;
using Renderer = Wrapper<SDL_Renderer>;
我想只允许创建 Wrapper class 的这些别名实例。原因之一是,这是对 SDL 资源指针的包装,它根据指针的类型具有不同的内存释放功能。
我想实现的最佳方案是使 Wrapper class 在我创建的别名的使用之外不可见。也许有一个使用匿名命名空间的解决方案,但解冻意味着包装器 class 不能在头文件中。
std::enable_if
怎么样,它将只为您的 classes/functions 启用某些类型?
看看 C++11 和 14 中的 type_traits。您可以进行各种静态检查(编译时检查)。例如,要检查类型是否符合您的预期,您可以使用:
std::is_same<T,int>::value
如果 T
是 int
,这将 return 在编译时 为真 。
我认为这会有所帮助
template <typename T, bool Allowed>
class WrapperBase;
template <typename T>
class WrapperBase<T, true>
{
};
template <typename T>
class WrapperBase<T, false>;
template < typename Type >
class WrapperBaseHelper : public WrapperBase<T, boost::is_base_of<SDL_Window, T>::value | boost::is_base_of<SDL_Renderer>::value ...e.t.c >
{
...
};
Best scenario I would like to achieve would be to make Wrapper class not visible outside the usage of aliases I create.
这可以使用 private
和包装器 class
class WrapperAccessor {
template < typename Type >
class Wrapper {
public:
Wrapper(Type* resource) : ptr(resource) {}
~Wrapper() { free(ptr); }
private:
Type* ptr;
};
public:
using Window = Wrapper<SDL_Window>;
using Renderer = Wrapper<SDL_Renderer>;
};
using Window = WrapperAccessor::Window;
using Renderer = WrapperAccessor::Renderer;
在你的具体情况下,我会使用 std::unique_ptr
,类似于:
template <typename T, T value> struct Call; // c++17 should allow Call<auto F>
template <typename T, void (*f)(T*)>
struct Call<void (*)(T*), f>
{
void operator ()(T* p) const { f(p); }
};
#define AUTO(F) decltype(F), F // not needed in C++17
using Window = std::unique_ptr<SDL_Window, Call<AUTO(&SDL_DestroyWindow)>>;
using Renderer = std::unique_ptr<SDL_Renderer, Call<AUTO(&SDL_DestroyRenderer)>>;
处理已删除的副本并更正与您的代码段相反的移动语义。