Ok, sau đây biên dịch cho tôi với VC10 và với GCC 4.5.1 (on ideone.com). Tôi nghĩ rằng tất cả các nhu cầu này của C++ 1x là <tuple>
, nên có sẵn (như std::tr1::tuple
) trong các trình biên dịch cũ hơn là tốt.
Nó vẫn cần bạn nhập một số mã cho mỗi thành viên, nhưng đó là mã rất nhỏ. (Xem giải thích của tôi ở cuối.)
#include <iostream>
#include <tuple>
typedef unsigned char uint8_t;
typedef unsigned char byte_t;
struct MsgData {
uint8_t num;
float x;
uint8_t elevation;
static const std::size_t buffer_size = sizeof(uint8_t)
+ sizeof(float)
+ sizeof(uint8_t);
std::tuple<uint8_t&,float&,uint8_t&> get_tied_tuple()
{return std::tie(num, x, elevation);}
std::tuple<const uint8_t&,const float&,const uint8_t&> get_tied_tuple() const
{return std::tie(num, x, elevation);}
};
// needed only for test output
inline std::ostream& operator<<(std::ostream& os, const MsgData& msgData)
{
os << '[' << static_cast<int>(msgData.num) << ' '
<< msgData.x << ' ' << static_cast<int>(msgData.elevation) << ']';
return os;
}
namespace detail {
// overload the following two for types that need special treatment
template<typename T>
const byte_t* read_value(const byte_t* bin, T& val)
{
val = *reinterpret_cast<const T*>(bin);
return bin + sizeof(T)/sizeof(byte_t);
}
template<typename T>
byte_t* write_value(byte_t* bin, const T& val)
{
*reinterpret_cast<T*>(bin) = val;
return bin + sizeof(T)/sizeof(byte_t);
}
template< typename MsgTuple, unsigned int Size = std::tuple_size<MsgTuple>::value >
struct msg_serializer;
template< typename MsgTuple >
struct msg_serializer<MsgTuple,0> {
static const byte_t* read(const byte_t* bin, MsgTuple&) {return bin;}
static byte_t* write(byte_t* bin, const MsgTuple&) {return bin;}
};
template< typename MsgTuple, unsigned int Size >
struct msg_serializer {
static const byte_t* read(const byte_t* bin, MsgTuple& msg)
{
return read_value(msg_serializer<MsgTuple,Size-1>::read(bin, msg)
, std::get<Size-1>(msg));
}
static byte_t* write(byte_t* bin, const MsgTuple& msg)
{
return write_value(msg_serializer<MsgTuple,Size-1>::write(bin, msg)
, std::get<Size-1>(msg));
}
};
template< class MsgTuple >
inline const byte_t* do_read_msg(const byte_t* bin, MsgTuple msg)
{
return msg_serializer<MsgTuple>::read(bin, msg);
}
template< class MsgTuple >
inline byte_t* do_write_msg(byte_t* bin, const MsgTuple& msg)
{
return msg_serializer<MsgTuple>::write(bin, msg);
}
}
template< class Msg >
inline const byte_t* read_msg(const byte_t* bin, Msg& msg)
{
return detail::do_read_msg(bin, msg.get_tied_tuple());
}
template< class Msg >
inline const byte_t* write_msg(byte_t* bin, const Msg& msg)
{
return detail::do_write_msg(bin, msg.get_tied_tuple());
}
int main()
{
byte_t buffer[MsgData::buffer_size];
std::cout << "buffer size is " << MsgData::buffer_size << '\n';
MsgData msgData;
std::cout << "initializing data...";
msgData.num = 42;
msgData.x = 1.7f;
msgData.elevation = 17;
std::cout << "data is now " << msgData << '\n';
write_msg(buffer, msgData);
std::cout << "clearing data...";
msgData = MsgData();
std::cout << "data is now " << msgData << '\n';
std::cout << "reading data...";
read_msg(buffer, msgData);
std::cout << "data is now " << msgData << '\n';
return 0;
}
Đối với tôi đây in
buffer size is 6
initializing data...data is now [0x2a 1.7 0x11]
clearing data...data is now [0x0 0 0x0]
reading data...data is now [0x2a 1.7 0x11]
(Tôi đã rút ngắn kiểu MsgData
của bạn để chỉ chứa ba thành viên dữ liệu, nhưng điều này chỉ là để thử nghiệm.)
Đối với mỗi loại thư, bạn cần xác định hằng số tĩnh buffer_size
và hai hàm get_tied_tuple()
thành viên, một const
và một số không const
, cả hai được triển khai theo cùng một cách. (Tất nhiên, những người này cũng có thể không phải là thành viên, nhưng tôi đã cố gắng giữ họ gần với danh sách các thành viên dữ liệu mà họ liên kết.)
Đối với một số loại (như std::string
), bạn sẽ cần phải thêm quá tải đặc biệt các chức năng detail::read_value()
và detail::write_value()
.
Phần còn lại của máy móc vẫn giữ nguyên cho tất cả các loại tin nhắn.
Với hỗ trợ đầy đủ C++ 1x, bạn có thể loại bỏ hoàn toàn việc loại bỏ các loại trả về rõ ràng của các hàm thành viên get_tied_tuple()
, nhưng tôi chưa thực sự thử điều này.
Tôi cho rằng sử dụng các loại tuple để xác định các thông báo, bạn có thể viết các mẫu chức năng lặp lại trên các thành viên tuple và gọi hàm trích xuất thích hợp cho bất kỳ loại nào bạn đang sử dụng. Tuy nhiên, tôi không thể nghĩ ra một ý tưởng để chuyển đổi tự động từ những bộ dữ liệu này sang cấu trúc khác. – sbi
Giả sử bạn đang sử dụng gói MSVC++ '#pragma (1)' nên hoạt động ngay cả trên các nền tảng khác. Việc đóng gói được thực hiện theo các thay đổi bit và mặt nạ, chứ không phải các bản sửa lỗi liên kết của hệ điều hành. –
Dữ liệu của bạn chưa được giải mã, chưa được căn chỉnh. Vì vậy, chỉ có cách chính xác để làm là truy cập byte khôn ngoan như 'giải nén' được gợi ý bởi @larsmans. – 9dan