我有一个(遗留)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_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函数.但我无法弄清楚如何做到这一点.
因为实现之间唯一的变化是第一个参数我只专注于那个部分:
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;
}