如何围绕 C 'class' 概括此 C++ 包装器?
How to generalize this C++ wrapper around a C 'class'?
我正在围绕 C 库编写 C++ 包装器。这是我的策略示例。
// header file
class LibrdfUri { // wrapper around librdf.h librdf_uri*
/*
* If the deleter of std::unique_ptr is an empty
* class then it can do some optimizations and
* not actually store the deleter object.
* Otherwise it has to accommodate extra space for
* the deleter, which is unnecessary
*
*/
struct deleter {
// turns deleter into a functor. For passing on to unique_ptr
void operator()(librdf_uri *ptr);
};
// automate management of librdf_uri* lifetime
std::unique_ptr<librdf_uri, deleter> librdf_uri_;
public:
LibrdfUri() = default;
explicit LibrdfUri(const std::string& uri); // construct from string
librdf_uri *get(); // returns the underlying raw pointer
};
// implementation
void LibrdfUri::deleter::operator()(librdf_uri *ptr) {
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
LibrdfUri::LibrdfUri(const std::string &uri) {
// create pointer to underlying C library 'object'
librdf_uri_ = std::unique_ptr<librdf_uri, deleter>(
librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()) // World::getWorld is static. Returns a pointer required by librdf_new_uri
);
}
librdf_uri *LibrdfUri::get() {
return librdf_uri_.get();
}
// and is used like so:
LibrdfUri uri("http://uri.com");
librdf_uri* curi = uri.get(); // when needed
这适用于单一类型 librdf_uri*
,它是基础库的一部分,但我有很多这样的类型。我的问题是双重的。第一部分涉及将此包装器推广到其他 classes 的最佳通用策略,而第二部分涉及该策略的实施。
关于第一部分,我的想法是:
1. 我可以像这里所做的那样手动实现每个 class。这可能是最简单和最不优雅的。但它仍然可能是我最好的选择。然而,其中涉及少量代码重复,因为我编写的每个 CWrapper 基本上都具有相同的结构。更不用说如果我需要更改某些内容,那么我将不得不单独执行每个 class。
2.使用基数class(抽象?)
3. 使用模板
我的问题的第二部分基本上是:如果我实施选项 2 或 3(我认为这甚至可能只是一个选项)我将如何做?
这是我所想的(严重损坏的)版本:
template<class LibrdfType>
class CWrapper {
struct deleter { ; //?
void operator()(LibrdfType *ptr) {
// ??
};
}
std::unique_ptr<LibrdfType, deleter> ptr;
public:
CWrapper() = default;
LibrdfType *get() {
ptr.get();
};
};
然后,LibrdfUri
和我需要包装的任何其他 C class,只需 subclass CWrapper
这是一个更好的删除器:
template<auto f>
using deleter=std::integral_constant< std::decay_t<decltype(f)>, f >;
使用:
deleter<librdf_free_uri>
是调用librdf_free_uri
的无状态删除器。
但我认为我们不需要。这是我可能会做的:
您需要3条信息。
- 如何构造
- 如何销毁
- 存储什么类型
一种方法是定义具有著名名称的 ADL baser 助手,您可以将其覆盖为 delete/construct。
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
template<class T>
void delete_wrapptr(T*)=delete;
struct cleanup_wrapptr{
template<class T>
void operator()(T* t)const{ delete_wrapptr(t); }
};
template<class T>
using wrapptr=std::unique_ptr<T, cleanup_wrapptr>;
template<class T>
wrapptr<T> make_wrapptr( tag_t<T>, ... )=delete;
现在您只需为 make 和 delete 编写重载。
void delete_wrapptr(librdf_uri* ptr){
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
librdr_uri* make_wrapptr(tag_t<librdf_uri>, const std::string &uri) {
return librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()); // World::getWorld is static. Returns a pointer required by librdf_new_uri
}
你可以;
wrapptr<librdf_uri> ptr = make_wrapptr(tag<librdf_uri>, uri);
实现只是覆盖了这两个函数。
您编写的 make_wrapptr
和 delete_wrapptr
重载需要在创建点以及 T
、tag_t
或 cleanup_wrapptr
的命名空间中可见。实现可以隐藏在cpp文件中,但重载的声明不能。
我正在围绕 C 库编写 C++ 包装器。这是我的策略示例。
// header file
class LibrdfUri { // wrapper around librdf.h librdf_uri*
/*
* If the deleter of std::unique_ptr is an empty
* class then it can do some optimizations and
* not actually store the deleter object.
* Otherwise it has to accommodate extra space for
* the deleter, which is unnecessary
*
*/
struct deleter {
// turns deleter into a functor. For passing on to unique_ptr
void operator()(librdf_uri *ptr);
};
// automate management of librdf_uri* lifetime
std::unique_ptr<librdf_uri, deleter> librdf_uri_;
public:
LibrdfUri() = default;
explicit LibrdfUri(const std::string& uri); // construct from string
librdf_uri *get(); // returns the underlying raw pointer
};
// implementation
void LibrdfUri::deleter::operator()(librdf_uri *ptr) {
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
LibrdfUri::LibrdfUri(const std::string &uri) {
// create pointer to underlying C library 'object'
librdf_uri_ = std::unique_ptr<librdf_uri, deleter>(
librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()) // World::getWorld is static. Returns a pointer required by librdf_new_uri
);
}
librdf_uri *LibrdfUri::get() {
return librdf_uri_.get();
}
// and is used like so:
LibrdfUri uri("http://uri.com");
librdf_uri* curi = uri.get(); // when needed
这适用于单一类型 librdf_uri*
,它是基础库的一部分,但我有很多这样的类型。我的问题是双重的。第一部分涉及将此包装器推广到其他 classes 的最佳通用策略,而第二部分涉及该策略的实施。
关于第一部分,我的想法是: 1. 我可以像这里所做的那样手动实现每个 class。这可能是最简单和最不优雅的。但它仍然可能是我最好的选择。然而,其中涉及少量代码重复,因为我编写的每个 CWrapper 基本上都具有相同的结构。更不用说如果我需要更改某些内容,那么我将不得不单独执行每个 class。 2.使用基数class(抽象?) 3. 使用模板
我的问题的第二部分基本上是:如果我实施选项 2 或 3(我认为这甚至可能只是一个选项)我将如何做?
这是我所想的(严重损坏的)版本:
template<class LibrdfType>
class CWrapper {
struct deleter { ; //?
void operator()(LibrdfType *ptr) {
// ??
};
}
std::unique_ptr<LibrdfType, deleter> ptr;
public:
CWrapper() = default;
LibrdfType *get() {
ptr.get();
};
};
然后,LibrdfUri
和我需要包装的任何其他 C class,只需 subclass CWrapper
这是一个更好的删除器:
template<auto f>
using deleter=std::integral_constant< std::decay_t<decltype(f)>, f >;
使用:
deleter<librdf_free_uri>
是调用librdf_free_uri
的无状态删除器。
但我认为我们不需要。这是我可能会做的:
您需要3条信息。
- 如何构造
- 如何销毁
- 存储什么类型
一种方法是定义具有著名名称的 ADL baser 助手,您可以将其覆盖为 delete/construct。
template<class T>struct tag_t{};
template<class T>constexpr tag_t<T> tag{};
template<class T>
void delete_wrapptr(T*)=delete;
struct cleanup_wrapptr{
template<class T>
void operator()(T* t)const{ delete_wrapptr(t); }
};
template<class T>
using wrapptr=std::unique_ptr<T, cleanup_wrapptr>;
template<class T>
wrapptr<T> make_wrapptr( tag_t<T>, ... )=delete;
现在您只需为 make 和 delete 编写重载。
void delete_wrapptr(librdf_uri* ptr){
librdf_free_uri(ptr); // this is the C library function for destruction of librdf_uri
}
librdr_uri* make_wrapptr(tag_t<librdf_uri>, const std::string &uri) {
return librdf_new_uri(World::getWorld(), (const unsigned char *) uri.c_str()); // World::getWorld is static. Returns a pointer required by librdf_new_uri
}
你可以;
wrapptr<librdf_uri> ptr = make_wrapptr(tag<librdf_uri>, uri);
实现只是覆盖了这两个函数。
您编写的make_wrapptr
和 delete_wrapptr
重载需要在创建点以及 T
、tag_t
或 cleanup_wrapptr
的命名空间中可见。实现可以隐藏在cpp文件中,但重载的声明不能。