如何使用模板化C ++结构定义C-forward声明的opaque结构

时间:2014-07-28 09:22:00

标签: c++ c templates

给出opaque类型的声明(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> {};

但是没有编译。

3 个答案:

答案 0 :(得分:1)

从我可以看出,这看起来是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强制转换回相应Internal<T>的{​​{1}}

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

值得注意的是cppreference,转换5,与C ++规范5.2.10相关。

  

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

     

Internal<T>

Live sample

答案 1 :(得分:1)

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

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

当您需要访问刚从指向模板类型的指针转​​发的数据时。

答案 2 :(得分:0)

也许工会有帮助?

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;
}