给定类型的模板化中间数组

时间:2018-08-14 15:47:55

标签: c++ function c++11 templates c++14

我有一个包含函数的库:

// Gets [bytes] number of *bytes* and fills rx_buff
void getData(uint8_t* rx_buff, uint16_t bytes);

我还有一个我正在为其编写接口的库,其结构相当简单(受保护的IP,所有名称都是虚构的):

[libGetData] <-> libMyLib <-> [libDoStuff]

我无法修改libGetData,也不能更改libDoStuff。 libDoStuff具有许多功能,如下所示:

bool isDataGood8(uint8_t input);
bool isDataGood16(uint16_t input);
bool isDataGood32(uint32_t input);
bool isDataGood64(uint64_t input);

我只想要一种干净的方法来实现getData()和所有isDataGoodXX()类型之间的中间函数。

template <typename T>
T getValue()
{
    // Create intermediate array for getData
    uint8_t temp_array[sizeof(T)];
    // Fill temp_array
    getData(&temp_array, sizeof(T));
    // Create value type to hold byte-array
    T return_val;
    // Copy array data into integer type
    std::memcpy(&return_val, temp_array, sizeof(T));
    return return_val;
}

此模板有效吗?

2 个答案:

答案 0 :(得分:3)

是的,此代码几乎是正确的,只有一点例外。您对getData的调用应如下所示:

getData(temp_array, sizeof(T));

您不应将 array 的地址传递到getValue函数中。除此之外,它还不错,并且不会遇到常见的严格混叠违规行为。

您还避免了任何对齐问题,并且代码是API所能提供的最佳代码。

答案 1 :(得分:0)

我看到的一个问题是,因为您仅在模板返回的值,所以您将需要显式指定类型以使用模板方法,即

auto val = getValue<uint32_t>();
isDataGood(val); // Should be!

如果不使用auto,则容易出现不匹配错误,并非所有错误都会报告:

uint32_t val = getValue<uint16_t>();
isDataGood(val); // perhaps not!

这取决于您希望如何避免这种情况,但是一种方法是使返回值成为一个参数,该参数允许推导模板类型:

uint32_t val;
getValue(val);
isDataGood(val); // Must be!

另一种方法是不使用原始整数,而始终使用包含该值的结构作为正确大小的成员。您无法像在整数大小之间那样在结构之间轻松切换。

另一种方法是让getValue返回一个包装,该包装针对给定类型知道如何强制转换为它,而对于其他类型,则在编译时强制转换失败:

struct FailIntBase 
{
  operator uint8_t()const = delete;
  operator uint16_t()const = delete;
  operator uint32_t()const = delete;
  operator uint64_t()const = delete;
  // etc
};
template <class Castable> struct SafeInt: FailIntBase
{
  Castable val;
  SafeInt(Castable val): val(val) {}
  operator Castable()const
  { return val; }
};

template <typename T>
SafeInt<T> getValue() { //...

// Testing:
auto X = getValue<uint16_t>();
uint16_t Y = getValue<uint16_t>();
uint32_t Z = getValue<uint16_t>(); //error: use of deleted function 'FailIntBase::operator uint32_t() const'

如果您需要涵盖更多类型(包括带符号类型),则可以使用信息量较少的错误消息来实现FailIntBase的更小实现:

conversion from 'SafeInt<short unsigned int>' to 'uint32_t' {aka 'unsigned int'} is ambiguous
note: candidate: 'SafeInt<Castable>::operator Castable() const [with Castable = short unsigned int]'
note: candidate: 'FailIntBase::operator uint64_t() const' <deleted>