打包结构,而不是在没有代码重复的情况下打包
Packed structures and not packed without code repetition
我有这个代码:
// size probably 4 bytes
struct NotPacked
{
uint16_t first;
uint8_t second;
};
// size is 3 bytes
struct Packed
{
uint16_t first;
uint8_t second;
}__attribute__((packed));
我想使用相同的结构,有时是包装的,有时不是。你知道有什么方法可以编写这段代码来避免重复吗?
[编辑]问题应该是:"..编写此代码,尽可能避免代码重复">
[编辑2]我尝试过使用空类优化的实验,但没有成功
[编辑3]添加了基本示例:
Packed packet;
receivePacketFromNetwork(&packet); // Fill the structure with data coming from the network
NotPacked notPacked = packedToUnpacked(packet); // convert packed structure to unpacked
processUnpacked(notPacked); // Do a lot of computations
我想使用相同的结构,有时是包装的,有时不是。你知道怎么写这个吗
没有。
您究竟如何期望由相同的代码定义两个完全不同的内存布局?
我能想到的唯一方法是使用丑陋的宏:
#define DEFINE_BOTH_STRUCTS(PACKED_NAME, REGULAR_NAME, ...)
struct PACKED_NAME { __VA_ARGS__ } __attribute__((packed));
struct REGULAR_NAME { __VA_ARGS__ }
然后用法
DEFINE_BOTH_STRUCTS(Packed, NotPacked,
char a;
int b;
char c[3];
);
这将从单个代码中定义两个变体。
还有一个不太理想的选择:
#define MY_STRUCT {
char a;
int b;
char c[3];
}
struct Packed MY_STRUCT __attribute__((packed));
struct NotPacked MY_STRUCT;
#undef MY_STRUCT
这是不太理想的,因为它需要为每个结构对定义一个宏,而前者只为整个程序定义一个宏。由于宏没有命名空间,因此可能会交互不良,因此建议尽量减少它们的使用(如果不可能完全避免它们(。
编辑:正如已经指出的那样,在第二种解决方案中undef
限制了污染。
此外,undef
可以重用同一个宏,而不会干扰其他宏名称。
这仍然是不完美的,因为其他一些代码可能依赖于它自己的独立 MY_STRUCT
宏观,我们对MY_STRUCT
的使用仍然可以通过无意中重新定义和后来取消定义来打破它。
您可以使用通用成员指针来访问它。
首先,在命名空间中定义成员:
namespace universal {
template<class T, unsigned int idx=0> struct member_ptr; // TODO
template<auto const*...> struct packed_struct; // TODO
template<auto const*...> struct unpacked_struct; // TODO
template<class...Ts> using variant=std::variant<Ts...>;
template<class...Ts> struct mutable_pointer:std::variant<Ts*...>{/*TODO*/};
template<class...Ts> using const_pointer = mutable_ptr<Ts const...>;
}
namespace Foo {
universal::member_ptr<int16_t> first;
universal::member_ptr<int8_t> second;
using packed = universal::packed_struct< &first, &second >;
using unpacked = universal::unpacked_struct< &first, &second >;
using either = universal::variant<packed, unpacked>;
using either_cptr = universal::const_pointer<packed, unpacked>;
using either_mptr = universal::mutable_pointer<packed, unpacked>;
}
然后你可以做:
void receivePacketFromNetwork( Foo::either_mptr ptr ) {
assert(ptr);
ptr->*Foo::first = 7;
ptr->*Foo::second = 3;
}
并让它适用于两种类型的结构。
用namespace universal
写东西并不容易,但并非不可能。
基本思想是重载operator->*
.
template<class T>
struct member_ptr {
template<class...Ts,
std::enable_if_t< supports<Ts>() && ..., bool> = true
>
T& operator->*( std::variant<Ts...>& lhs, member_ptr const& self ) {
return std::visit(
[&self]( auto&& lhs )->T&{ return lhs->*self; },
lhs
);
}
template<class U>
constexpr static bool supports(); //TODO
};
template<auto const* a, auto const* b, auto const*... bs>
struct unpacked_struct<a, b, bs...>:
unpacked_struct<a>,
unpacked_struct<b, bs...>
{
using unpacked_struct<a>::operator->*;
using unpacked_struct<b, bs...>::operator->*;
};
template<class T, , unsigned int idx, member_ptr<T, idx> const* a>
struct unpacked_struct<a> {
T data;
T& operator->*( member_ptr<T, idx> const& ) & {
return data;
}
T&& operator->*( member_ptr<T, idx> const& ) && {
return std::move(data);
}
T const& operator->*( member_ptr<T, idx> const& ) const& {
return data;
}
T const&& operator->*( member_ptr<T, idx> const& ) const&& {
return std::move(data);
}
};
等。
相关文章:
- 这个c++代码是如何在没有定义函数的情况下运行的
- 如何在没有函数的情况下编写此代码并使C++更简单?
- 在什么情况下,我想在 C/C++ 代码中使用内联汇编代码
- 可以在没有构建代码的情况下转到定义吗?
- 在没有引用传递资源的情况下,如何在java中简化这些代码
- 尝试在不使用转换概念的情况下呈现此代码
- 寻找有关为什么此C++代码在没有引用的情况下不起作用的解释
- 在运行时,何时完全初始化 std 库才能在不破坏代码的情况下使用它?
- 在存在错误代码的情况下输出参数与 NRVO
- 在给定相同的输入的情况下,某些代码怎么可能花费更多时间来运行,这似乎只是因为它处于循环中?
- 在链接的程序集文件中,我想从 c++ 调用代码访问变量.是否可以在不触发访问冲突的情况下执行此操作?
- 为什么我的代码在没有 chroot 函数的情况下工作,但使用 chroot 函数失败?
- 如何在不复制此代码的情况下将多个函数放入多个命名空间?
- 如何在 C++03 中没有重复代码的情况下在堆栈上创建一个非常量 C 字符串数组?
- 在没有额外代码的情况下链接两个独立类的最通用方法是什么?
- 如何在没有性能命中的情况下抽象SIMD代码来处理不同的数据类型
- 为什么 GCC 6.3 在没有显式 C++11 支持的情况下编译此大括号初始化列表代码
- 打包结构,而不是在没有代码重复的情况下打包
- 如何在不中断剩余代码的情况下仅C++中输入整数
- 如何在<typename> <long> 不更改给定代码的情况下将自定义向量与 STL 向量相互转换?