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