在旧版C接口的接口映射中使用模板来参数化类型

时间:2018-08-13 10:38:11

标签: c++ templates

我有一个(旧版)c接口,看起来像这样:

// c interface
#include <stdint.h>
#include <string.h>

typedef enum {
    type_1 = 0, /* native type: uint8_t */
    type_2 = 1, /* native type: double */
    // ... lots of more types defined ...
} thing_type_t;

void thing_set(thing_type_t type, size_t type_size, void* value);
void thing_get(thing_type_t type, size_t type_size, void* return_value);

void thing_set_type_1(uint8_t value);
void thing_get_type_1(uint8_t *value);

void thing_set_type_2(double value);
void thing_get_type_2(double *value);

// ...

因此,基本上,您可以设置 thing ,并根据选择的thing_type_t来确定对应的本机类型。我无法更改此界面。

现在,我想使用类型多态性来创建C ++接口,因此我从客户端可以执行以下操作:

// C++ client
#include <cstdint>

int main(void)
{
    Thing thing;
    thing.set(std::uint8_t(42));
    thing.set(42.0);

    auto uivalue = thing.get<std::uint8_t>();
    auto dvalue = thing.get<double>();

    return 0;
}

它不必完全像这样,但是其思想是客户端不必担心内部thing_type_t类型,而只需要使用相应的本机类型即可。

我想出的是使用这样的模板:

// C++ interface
#include <cstdint>

class Thing
{
public:
    template <typename T> void set(T value);
    template <typename T> T get();
};

template <> void Thing::set(uint8_t value)
{
    thing_set(type_1, sizeof value, reinterpret_cast<void*>(&value));
}
template <> std::uint8_t Thing::get()
{
    uint8_t ret = 0;
    thing_get(type_1, sizeof ret, &ret);
    return ret;
}

template <> void Thing::set(double value)
{
    thing_set(type_2, sizeof value, reinterpret_cast<void*>(&value));
}
template <> double Thing::get()
{
    double ret = 0;
    thing_get(type_2, sizeof ret, &ret);
    return ret;
}

即我正在为每个thing_type_t进行类型专用化,这会导致膨胀的代码以及大量的重复代码。

如何简化此过程,以便可以表达thing_type_t与本机类型之间的映射,而不必一次又一次地复制get / set函数?

我觉得我应该可以通过thing_type_t和本机类型以及映射参数化get和set函数的参数。但是我不知道该怎么做。

Online editable example

2 个答案:

答案 0 :(得分:5)

在实现之间唯一改变的是第一个参数,我只是专门介绍该部分:

class Thing
{
public:
    template <typename T> void set(T value)
    {
        thing_set(getType<T>(value), sizeof value, reinterpret_cast<void*>(&value));
    }
    template <typename T> T get()
    {
        T ret = 0;
        thing_get(getType<T>(ret), sizeof ret, &ret);
        return ret;
    }

private:
    template <typename T> thing_type_t getType(T);
};

template <> thing_type_t Thing::getType(uint8_t)
{
    return type_1;
}
template <> thing_type_t Thing::getType(double)
{
    return type_2;
}

答案 1 :(得分:0)

macroses在这种情况下可以提供帮助:

typemap.h

macro(type_1, std::uint8_t)

thing.h

class Thing
{
public:
    template <typename T> void set(T value);
    template <typename T> T get();
};

#define macro(thing_type, actual_type) template <> void Thing::set(actual_type value) \
{\
    thing_set(thing_type, sizeof value, reinterpret_cast<void*>(&value));\
}\
#include <typemap.h>
#undef macro 

#define macro(thing_type, actual_type) template <> actual_type Thing::get()\
{\
    actual_type ret = 0;\
    thing_get(thing_type, sizeof ret, &ret);\
    return ret;\
}\
#include <typemap.h>
#undef macro

所以最后您只需要修改typemap.h即可添加/删除专业化