如何使用模板化C++结构定义 C 向前声明的不透明结构

How to define C-forward declared opaque struct with a templated C++ struct

本文关键字:结构 声明 不透明 定义 C++ 何使用      更新时间:2023-10-16

给定不透明类型的C声明(cheader.h(

typedef struct internal_data * Opaque;

我想声明"internal_data"作为模板的实例(cppheader.h(

namespace Lib {
template<typename T>
struct Internal {
    T data;
};
template<typename T>
Internal<T>* Initialise(T data) {
    Internal<T>* t = new Internal<T>();
    t->data = data;
    return t;
}
}

以便编译以下函数:

#include "cppheader.h"
#include "cheader.h"
int main(int argc, char** argv)
{
    Opaque o = Lib::Initialise(argc);
    return 0;
}

我无法修改 C 标头。C++标题没有公开,所以我可以随意修改该标头。实例化的模板必须是 POD。为了简单起见,我省略了 C 标头上的多个不透明类型。它们都应该取消对C++模板实例的引用。

我试过了

typedef Lib::Internal<int> internal_data;

struct internal_data : Lib::Internal<int> {};

但两者都不编译。

如果你不想reinterpret_cast<>,你可以从虚拟internal_data继承,即

struct internal_data {};
template<typename T>
struct Internal: internal_data {
    T data;
};

当您需要访问数据时,只需从指针向下转换为模板类型。

据我所知,这看起来像是典型的 C 到 C++ API 映射,反之亦然。

鉴于无法更改 C 头文件,则 Opaque 的定义受到约束,基本上无法键入到头文件中包含的任何C++构造C++。

纯粹的意义上,它有点丑陋,但你可以为此使用reinterpret_cast

在 cppheader 中;

struct internal_data {};
template<typename T>
struct Internal {
    T data;
};
template <typename T>
Opaque map_internal(Internal<T>* p)
{
  return reinterpret_cast<Opaque>(p);
}
template <typename T>
Internal<T>* remap_internal(Opaque p)
{
  return reinterpret_cast<Internal<T>*>(p);
}

然后内部Initialise更改为;

template<typename T>
Opaque Initialise(T data) {
    Internal<T>* t = new Internal<T>();
    t->data = data;
    return map_internal(t);
}

您没有提及有关资源管理的任何内容,但map_internal的反面可用于在需要时将Opaque转换回相应deleteInternal<T>

注意:类型安全在这里是一个问题(w.r.t.reinterpret_cast(,但在这种情况下,权衡是类型安全与互操作性。由于严格的别名,您不应尝试访问可能(将来(在internal_data中的任何数据,它只是为了从Internal<T>转换和转换回

这里值得注意的是cpp首选项,转换5,与C++规范5.2.10有关。

指向

T1 类型的对象的任何指针都可以转换为指向另一种类型 cv T2 的对象的指针。这完全等同于

static_cast<cv T2*>(static_cast<cv void*>(expression)) .

现场样品

也许工会会有所帮助?

template<typename T>
union InternalExtend
{
    Internal<T>* internal;
    Opaque opaque;
};
template<typename T>
Opaque Initialise(T data) {
    InternalExtend<T> ret;
    ret.internal = new Internal<T>();
    ret.internal->data = data;
    return ret.opaque;
}