我必须检查某人使用20多个联合的笨拙代码,并根据数字方法对数据进行处理并将数据复制到字节数组中,以便通过模板实现这些方法(第二个用于char )
template <class T> class type_punner
{
T& p;
unsigned char* pun;
public:
type_punner(T& ref): p (ref), pun(reinterpret_cast<unsigned char*>(&p))
{
static_assert(std::is_pod<T>::value, "type_punner can be used only for POD");
}
inline unsigned char& at(std::size_t i)
{
#ifdef QT_DEBUG
if(!(i < size())) throw std::out_of_range( __FUNCTION__ );
#endif
#if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
return pun[i];
#else
return pun[size() - i - 1];
#endif
}
inline unsigned char& reverse_at(std::size_t i)
{
#ifdef QT_DEBUG
if(!(i < size())) throw std::out_of_range(__FUNCTION__);
#endif
#if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
return pun[size() - i - 1];
#else
return pun[i];
#endif
}
// = 0 is LSB
inline unsigned char& operator[](std::size_t i)
{
return at(i);
}
inline std::size_t size()
{
return sizeof(T);
}
};
如果我保持标准兼容并通过返回的引用分配新值,那么我只担心这一点。
答案 0 :(得分:1)
您的代码看似合法。有一些改进:
constexpr bool k_little_endian
#if (Q_BYTE_ORDER == Q_LITTLE_ENDIAN)
= true;
#else
= false;
#endif
constexpr bool k_debug
#ifdef QT_DEBUG
= true;
#else
= false;
#endif
template <class T,
bool little_endian = k_little_endian,
bool debug = k_debug
>
class type_punner {
T* p;
unsigned char* pun() const { return reintepret_cast<unsigned char*>(p); }
public:
static_assert(std::is_pod<T>::value, "type_punner can be used only for POD");
type_punner(T& ref):
p (std::addressof(ref))
{}
type_punner(type_punner const&)=default;
type_punner()=delete;
unsigned char& at(std::size_t i) const noexcept(!debug) {
if (debug && !(i<size())) throw std::out_of_range( __FUNCTION__ );
if (little_endian)
return pun()[i];
else
return pun()[size() - i - 1];
}
unsigned char& reverse_at(std::size_t i) const noexcept(!debug) {
if(debug && !(i < size())) throw std::out_of_range(__FUNCTION__);
if (little_endian)
return pun()[size() - i - 1];
else
return pun()[i];
}
// = 0 is LSB
unsigned char& operator[](std::size_t i) const noexcept(!debug) {
return at(i);
}
static constexpr std::size_t size() noexcept(true) { return sizeof(T); }
};
首先,这会将宏移开。您正在查看的代码往往更易于推理,编译器完全能够消除死分支。除非您希望在类型上使用引用语义,否则很少存储引用,并且在同一个类/结构中将引用存储在非引用旁边几乎不是一个好主意。< / p>
其次,类体中的内联是多余的。
第三,size
既是constexpr又是静态的。
第四,使用默认副本/分配的T&
并不做任何合理的事情。 T*
。所以我使用了T*
。
第五,无需存储pun
。每次生成它都是零成本。
请注意,上述type_punner
可以在大端环境中试用little_endian
,或者只针对遇到问题的部分进行调试。这是一个很小的编译时间。
答案 1 :(得分:0)
如果我保持标准兼容并通过返回的引用分配新值,那么我只担心这一点。
它是有效的,因为那些引用是窄字符类型,这是特殊的。