C++ 一个C++;模板是否专门用于所有32位POD类型?

C++ 一个C++;模板是否专门用于所有32位POD类型?,c++,templates,endianness,template-specialization,specialization,C++,Templates,Endianness,Template Specialization,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(

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

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;
    }
}
这种专门化也适用于32位整数,有符号或无符号,因此我有一大堆只有类型名不同的重复项

如何通过这个模板路由所有4字节POD类型的实例化?(顺便说一句,我愿意以不同的方式解决这个问题,但在这种情况下,我想确切地知道是否有可能构建这种元专门化模板。)


编辑:谢谢大家,在阅读了答案并意识到算术比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);
}
template struct SwapEndian{template static inline void};
模板模板内联void SwapEndian::uu(T&ptr){
//…这里的东西。。。
}
// ... 这里有更多的东西。。。
模板内联空白SwapEndian(T&ptr){
静态_断言(是_算术::值,“非算术类型不支持Endian交换”);
SwapEndian::模板(ptr);
}

如有疑问,请发送标签

这个实现有两个特点--
是pod
获取大小的t
。基本覆盖将这两个标记的特征分派到
SwapEndian
s。还有一个
is_pod
覆盖,以及一个非pod类型的覆盖(我建议
=delete
ing)

扩展到新的性状和类型相对容易

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>{});
}
模板
使用sizeof_t=std::integral_常量;
模板
使用get_sizeof_t=sizeof_t;
模板
void-SwapEndian(T&T,标准::真_-type/*为pod*/,尺寸){

std::cout我正在使用一个单独的
SwapEndian
SwapEndianImpl
,这样我们就可以使用模板推导和部分专门化

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);
}
模板结构SwapEndianImpl
{
模板静态内联无效函数(t&n);
};
模板模板void SwapEndianImpl::Func(t&n)
{

std::cout您可以将交换限制在算术类型上(不使用所有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);
}
#包括
#包括
#包括
名称空间详细信息{
模板<
类型名T,
无符号N=sizeof(T)*字符位,
bool Swap=std::is_算术::value>
SwapEndian结构
{
静态无效应用(T&){

真是太好了!这似乎是对的……只要豆荚类型公开它们的大小()在一个兼容的上下文中。--至于现在,我想这是棺材里的钉子,我被重复的东西卡住了。@OmniPotential实体概念,虽然很棒,但只是语法上的糖分。好吧,从技术上讲,我们可以有一台具有16位字符的机器。所以
CHAR\u bit*sizeof(T)==32
将是一个更好的条件,不是吗?(编辑:我一定忽略了你提到的假设,但仍然如此)@Columbo同意。但是如果这是你的项目中第一个当
CHAR\u BIT
不等于
8
时中断的代码块,那么,我不相信你。:)@Columbo也被重写,因为标记分派更干净。@MichaelGazonda专门化必须是完整的,并且不会更改选择的重载。它只是更改所选重载的实现。模板类型的专门化会更改所选的专门化及其实现。在标记分派之间转到template type和SFINAE,您可以在不使用专门化的情况下获得所需的工具超载太多,人们经常会混淆它们,这会导致意外的调度。有一些罕见的用例,但即使如此,也很脆弱。@ MichaelGazonda,你所说的运行时是什么?C++语言标准,在运行时,机器在正确写的标签调度“调用”中不需要做任何工作。。返回值可以完全省略,转发也足够完美(引用和琐碎的无状态类型很多)。编译器可以自由地进行反优化,但面对一些敌人,我们无法取胜:我们必须假设编译器的QoI是可接受的。
#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);
}