刚刚解决了同样的问题。使用串行通信与机器人一起工作。有很多很多的消息格式,所以我需要一种方法来将每条消息映射到消息中的类型。然后根据类型将消息uint8_t字节转换为类型。
它使用tuple 类型列出消息中的预期类型。每种类型都会调整消息中的位置指针。该代码演示了在循环或单个片段中处理传入消息。
它适用于 C++17 和 C++20。这是我的“让它工作的代码”,所以有一些一般的输出可以用来观察正在发生的事情。我对真实代码做了一些改进,但留给读者作为练习。
直播版here.
#include <iostream>
#include <string>
#include <string_view>
#include <tuple>
using Msg = std::basic_string<std::uint8_t>;
//==========================================================================================================================================
template <class... Ts>
struct overloaded : Ts... {
using Ts::operator( )...;
};
#if (_cplusplus != 202002L) // check for C++17 or C++20
// Deduction guide, google `CTAD for aggregates` for more info
template <class... Ts>
overloaded(Ts...) -> overloaded<Ts...>; // not needed before C++20
#endif
auto emit = overloaded {
[](const auto& b) {
std::cout << "From auto: " << std::boolalpha << b << std::noboolalpha << '\n';
},
[](const char& b) {
std::cout << "From char: ";
if (std::isprint(b)) {
std::cout << std::showbase << b;
} else if (b != 0) {
std::cout << '\\' << (uint16_t(b) & 0xFF);
} else {
std::cout << '\\' << 0; // showbase does not output 0x for zero
}
std::cout << '\n';
},
[](const uint8_t& b) {
std::cout << "From uint8_t: " << std::showbase << (uint16_t)b << '\n';
},
[](const int8_t& a) {
std::cout << "From int8_t: " << int16_t(a) << '\n';
},
[](const uint16_t& a) {
std::cout << "From uint16_t: " << std::showbase << a << '\n';
},
};
//----------------------------------------------------------------------------------------------------------------
template <class... Ts>
struct msg_proc : Ts... {
using Ts::operator( )...;
};
#if (__cplusplus != 202002L)
// Deduction guide, google `CTAD for aggregates` for more info
template <class... Ts>
msg_proc(Ts...) -> msg_proc<Ts...>; // not needed from C++20
#endif
auto load = msg_proc {
[](Msg const& msg, int16_t& pos, bool& value) {
value = (msg[pos++] != 0);
},
[](Msg const& msg, int16_t& pos, char& value) {
value = msg[pos++];
},
[](Msg const& msg, int16_t& pos, uint8_t& value) {
value = msg[pos++];
},
[](Msg const& msg, int16_t& pos, int8_t& value) {
value = msg[pos++];
},
[](Msg const& msg, int16_t& pos, int16_t& value) {
value = (msg[pos] << 8) + msg[pos + 1];
pos += 2;
},
[](Msg const& msg, int16_t& pos, uint16_t& value) {
value = (msg[pos] << 8) + msg[pos + 1];
pos += 2;
},
};
//----------------------------------------------------------------------------------------------------------------
template <typename... Ts>
void emitter(std::tuple<Ts...> tup) {
std::apply([](const auto&... e) {
(emit(e), ...);
},
tup);
}
//----------------------------------------------------------------------------------------------------------------
template <typename T>
void emitter(T const& value) {
emit(value);
}
//----------------------------------------------------------------------------------------------------------------
template <typename... Ts>
auto converter(Msg const& msg) {
std::tuple<Ts...> tup { };
int16_t pos { };
std::apply(
[&](auto&... e) {
(load(msg, pos, e), ...);
},
tup);
std::cout << "pos " << pos << '\n';
return tup;
}
//----------------------------------------------------------------------------------------------------------------
int main( ) {
Msg msg { 0x01, 1, 0x57, 0x58, 0x12, 0x34, 0xDE, 0xAD };
auto& b_c = converter<bool, char, uint8_t, int8_t, int16_t, uint16_t>;
auto res = b_c(msg);
emitter(res);
std::cout << '\n';
emitter(std::get<0>(res));
emitter(std::get<1>(res));
emitter(std::get<2>(res));
emitter(std::get<3>(res));
std::cout << '\n';
return 0;
}