簡體   English   中英

如何將C ++模板專門用於所有32位POD類型?

[英]How can a C++ template be specialized for all 32-bit POD types?

我開發了一個簡單的模板函數來交換單個字段的字節順序:

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;
    }
}

我經常在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
}

這個專門化也適用於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);
}

如有疑問,請發送標簽。

此實現有2個特征 - is_podget_sizeof_t 基本覆蓋將調度到具有標記的兩個特征的SwapEndian 對於非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>{});
}

我不確定這是不是一個好主意,但上面應該這樣做。

使用一些C ++ 14功能。 假設CHAR_BIT8

您應該很少專門化模板功能。 而是超載。 標簽調度為您提供了重載解析功能,可以調度在編譯時運行的代碼。

實例

我正在使用單獨的SwapEndianSwapEndianImpl以便我們可以使用模板推導和部分特化。

template<bool> struct SwapEndianImpl
{
    template<typename t> static inline void Func(t& n);
};
template<> template<typename t> void SwapEndianImpl<false>::Func(t& n)
{
    std::cout << "not 32bit pod" << std::endl;
}
template<> template<typename t> void SwapEndianImpl<true>::Func(t& n)
{
    std::cout << "32bit pod" << std::endl;
}

template<typename t> inline void SwapEndian(t& n)
{
    SwapEndianImpl<std::is_pod<t>::value && sizeof(t) == (32 / CHAR_BIT)>::template Func<t>(n);
}

我相信如果你專注於兩個以上的條件,這比SFINAE更好。

您可能會限制算術類型的交換(不使用所有POD類型),並使用專門的模板類來提高靈活性:

#include <climits>
#include <iostream>
#include <type_traits>

namespace Detail {
    template <
        typename T,
        unsigned N = sizeof(T) * CHAR_BIT,
        bool Swap = std::is_arithmetic<T>::value>
    struct SwapEndian
    {
        static void apply(T&) {
            std::cout << "Not Swapping\n";
        }
    };

    template <typename T>
    struct SwapEndian<T, 16, true>
    {
        static void apply(T&) {
            std::cout << "Swapping\n";
        }
    };

    template <typename T>
    struct SwapEndian<T, 32, true>
    {
        static void apply(T&) {
            std::cout << "Swapping\n";
        }
    };

    template <typename T>
    struct SwapEndian<T, 64, true>
    {
        static void apply(T&) {
            std::cout << "Swapping\n";
        }
    };
}

template <typename T>
void SwapEndian(T& value) {
    Detail::SwapEndian<T>::apply(value);
}

struct Structure
{
    char s[4];
};
static_assert(std::is_pod<Structure>::value, "Should be POD");


int main() {
    char c;
    short s;
    int i;
    long long l;
    float f;
    double d;
    void* p;
    Structure structure;
    SwapEndian(c);
    SwapEndian(s);
    SwapEndian(i);
    SwapEndian(l);
    SwapEndian(f);
    SwapEndian(d);
    SwapEndian(p);
    SwapEndian(structure);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM