如何将C++模板专门用于所有32位POD类型?

Mic*_*kLH 4 c++ templates endianness specialization template-specialization

我开发了一个简单的模板函数来交换单个字段的字节顺序:

template <typename T> inline void SwapEndian(T& ptr) {
    char *bytes = reinterpret_cast<char*>(&ptr);
    int a = sizeof(T) / 2;
    while (a--) {
        char tmp = bytes[a];
        int b = sizeof(T) - 1 - a;
        bytes[a] = bytes[b];
        bytes[b] = tmp;
    }
}
Run Code Online (Sandbox Code Playgroud)

我会经常在T = intfloat.这两种类型在目标平台上由4个字节表示,并且可以由模板的相同特化处理.

因为这个函数有时负责处理原始数据的大缓冲区,所以我创建了一个优化的特化:

template<> inline void SwapEndian(float& ptr) {
    #if defined(__GNUC__)
        *reinterpret_cast<unsigned*>(&ptr) = __builtin_bswap32(*reinterpret_cast<unsigned*>(&ptr));

    #elif defined(_MSC_VER)
        *reinterpret_cast<unsigned*>(&ptr) = __byteswap_ulong(*reinterpret_cast<unsigned*>(&ptr));

    #endif
}
Run Code Online (Sandbox Code Playgroud)

这个专门化也适用于32位整数,有符号或无符号,所以我有一大堆重复,只有类型名称不同.

如何通过这个模板路由所有4字节POD类型的实例?(PS.我愿意以不同的方式解决这个问题,但在这种情况下,我想明确知道是否可以构建这些元专用模板.)


编辑:谢谢大家,在阅读了答案并意识到算术比pod更好的限制之后,我受到了启发,写了一些东西.所有答案都很有用,但我只能接受一个,所以我接受了一个似乎在结构上相同的答案.

template<bool, bool> struct SwapEndian_ { template<typename T> static inline void _(T&); };
template<> template<typename T> inline void SwapEndian_<true, true>::_(T& ptr) {
    // ... stuff here ...
}
// ... more stuff here ...
template<typename T> inline void SwapEndian(T& ptr) {
    static_assert(is_arithmetic<T>::value, "Endian swap not supported for non-arithmetic types.");
    SwapEndian_<sizeof(T) & (8 | 4), sizeof(T) & (8 | 2)>::template _<T>(ptr);
}
Run Code Online (Sandbox Code Playgroud)

Yak*_*ont 7

如有疑问,请发送标签.

这个实现有两个特点 - is_podget_sizeof_t.基本覆盖将调度为SwapEndian具有标记的两个特征的s.对于非pod类型is_pod,还有一个覆盖和覆盖(我建议=delete).

扩展到新的特征和类型相对容易.

template<size_t n>
using sizeof_t = std::integral_constant<size_t, n>;
template<class T>
using get_sizeof_t = sizeof_t<sizeof(T)>;

template <class T>
void SwapEndian(T& t, std::true_type /*is pod*/, sizeof_t<4>) {
  std::cout << "4 bytes!\n";
  // code to handle 32 bit pods
}
template <class T, size_t n>
void SwapEndian(T& t, std::true_type /*is pod*/, sizeof_t<n>) {
  std::cout << "pod\n";
  // code to handle generic case
}
template <class T, size_t n>
void SwapEndian(T& t, std::false_type /*is pod*/, sizeof_t<n>) {
  std::cout << "not pod\n";
  // probably want to =delete this overload actually 
}
template<class T>
void SwapEndian(T& t) {
    SwapEndian(t, std::is_pod<T>{}, get_sizeof_t<T>{});
}
Run Code Online (Sandbox Code Playgroud)

我不确定这是不是一个好主意,但上面应该这样做.

使用一些C++ 14功能.假设CHAR_BIT8.

您应该很少专门化模板功能.而是超载.标签调度为您提供了重载解析功能,可以调度在编译时运行的代码.

实例

  • 好吧,从技术上讲,我们可以拥有一台带有16位字符的机器.所以`CHAR_BIT*sizeof(T)== 32`将是一个更好的条件,不是吗?(编辑:我一定忽略了你提到的假设,但仍然) (4认同)