将变量模板限制为类型列表

Limit variable template to a list of types

本文关键字:类型 列表 变量      更新时间:2023-10-16

我正试图通过添加智能指针来使一些GStreamer代码现代化。例如:

GstElement *pipeline = gst_pipeline_new("test-pipeline");
gst_object_unref(pipeline);

可以重写:

struct GstElementDeleter {
void operator()(GstElement* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GstElementDeleter> pipeline = gst_pipeline_new("test-pipeline");

gst_object_unref()可以在任何gpointer上使用,因此可以重写:

template<typename T>
struct GPointerDeleter {
void operator()(T* p) { gst_object_unref(p); }
};
std::unique_ptr<GstElement, GPointerDeleter<GstElement>> pipeline = gst_pipeline_new("test-pipeline");

但我想做的是将其限制为仅处理可以使用gst_object_unref解除分配的类型。有没有一种方法可以声明模板只适用于类型列表GstElementGstBus等?

也许您可以将模板设为operator()(因此无需显式定义智能指针的模板参数(,并使用SFINAE仅为允许的类型启用operator()

struct GPointerDeleter
{
template <typename T>
typename std::enable_if<std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */
>::type operator() (T * p) const
{ gst_object_unref(p); }
};

或者,也许更好的是,您可以在operator()中添加(如Jarod42(谢谢(所建议的(static_assert()检查

struct GPointerDeleter
{
template <typename T>
void operator() (T * p) const
{
static_assert( std::is_same<T, GstElement>::value
|| std::is_same<T, GstBus>::value
/* or other cases */, "some error message" );
gst_object_unref(p);
}
};

也许是类型特征?如果您以前没有见过这些内容,请参阅<type_traits>

template<typename T>
struct can_gst_unref : std::false_type { };
// for each type...
template<> struct can_gst_unref<GstElement> : std::true_type { };
// convenient alias, as is convention for type traits
template<typename T>
inline constexpr bool can_gst_unref_v = can_gst_unref<T>::value;
// now conditionally define operator() in your deleter
struct GstDeleter {
template<typename T>
std::enable_if_t<can_gst_unref_v<T>> operator()(T* p) { gst_object_unref(p); }
};
// Making the function a template instead of the class reduces clutter at usage
std::unique_ptr<GstElement, GstDeleter> works(gst_pipeline_new("test-pipeline"));
// can_gst_unref is not specialized to std::string
// so the general case takes over, and gives can_gst_unref_v<std::string> = false
// std::enable_if_t thus doesn't produce a type, and operator() is not defined, because it has no return type
// therefore, this doesn't compile
std::unique_ptr<std::string, GstDeleter> whoops;