用于重新排序无符号整数的 Constexpr Variadic 模板
Constexpr Variadic Template to reorder unsigned integers
我正在使用首先发送最低 8 位字的外设。所以第一个字(在本例中是发送 16 位)必须在右侧。如变量 v1
.
所示
我想要一个更具表现力的版本,所以我想添加一个 constexpr 函数,将第一个参数移动到结果整数的最右边位置。同时仍将其用作函数的第一个参数。
我真的没有想出一个好的解决方案。当我建立一个 "shift value" 并在离开递归时减少它。此外,这在 constexpr
环境中不起作用,这对我来说是 "no go"。也许你们有人有建议?
我确实尝试了很多东西。但大多不工作。折叠表达式也没有真正帮助。
Cpp版本无所谓(c++2a也可以)
// send 0x05 first then 0xFF
std::uint16_t v1 = (0xFFU << 8U | 0x05U); // right align first 8bit word so it is send first
std::uint16_t v2 = lower_word_first(0x05U, 0xFFU);
// lower_word_first
static std::size_t shift = 0;
auto lower_word_first(){
return 0;
}
template<typename unsigned_word_type, typename... words>
auto lower_word_first(unsigned_word_type word, words... ws){
shift += 1;
auto val = lower_word_first(ws...); // just for debugging purposes split into val
auto res = val | word << (shift - 1) * 8U;
shift -= 1;
return res;
}
#include <cstddef>
#include <utility>
template <std::size_t... Is, typename... Ws>
constexpr auto lower_word_first(std::index_sequence<Is...>, Ws... ws)
{
return ((ws << Is*8) | ...);
}
template <typename... Ws>
constexpr auto lower_word_first(Ws... ws)
{
return lower_word_first(std::index_sequence_for<Ws...>{}, ws...);
}
在这里,std::index_sequence_for
,例如
std::index_sequence_for<A, B, C, D>
产生:
std::index_sequence<0, 1, 2, 3>
然后折叠表达式变成:
(ws_0 << 0*8) | (ws_1 << 1*8) | (ws_2 << 2*8) | (ws_3 << 3*8)
或者,将参数存储在数组中,然后反向迭代。
具有一些 c++20 功能,以及一个强制特定类型的辅助函数,它看起来像:
#include <cstdint>
#include <array>
#include <ranges>
#include <concepts>
template <typename T>
auto type()
{
if constexpr (std::is_same_v<T, std::uint8_t>) return std::uint16_t{};
if constexpr (std::is_same_v<T, std::uint16_t>) return std::uint32_t{};
if constexpr (std::is_same_v<T, std::uint32_t>) return std::uint64_t{};
}
template <std::integral W>
constexpr auto lower_word_first(W w, std::same_as<W> auto... ws)
{
decltype(type<W>()) val{};
const std::array a = { w, ws... };
for (auto v : std::ranges::reverse_view{ a }) {
val <<= 8;
val |= v;
}
return val;
}
我正在使用首先发送最低 8 位字的外设。所以第一个字(在本例中是发送 16 位)必须在右侧。如变量 v1
.
我想要一个更具表现力的版本,所以我想添加一个 constexpr 函数,将第一个参数移动到结果整数的最右边位置。同时仍将其用作函数的第一个参数。
我真的没有想出一个好的解决方案。当我建立一个 "shift value" 并在离开递归时减少它。此外,这在 constexpr
环境中不起作用,这对我来说是 "no go"。也许你们有人有建议?
我确实尝试了很多东西。但大多不工作。折叠表达式也没有真正帮助。 Cpp版本无所谓(c++2a也可以)
// send 0x05 first then 0xFF
std::uint16_t v1 = (0xFFU << 8U | 0x05U); // right align first 8bit word so it is send first
std::uint16_t v2 = lower_word_first(0x05U, 0xFFU);
// lower_word_first
static std::size_t shift = 0;
auto lower_word_first(){
return 0;
}
template<typename unsigned_word_type, typename... words>
auto lower_word_first(unsigned_word_type word, words... ws){
shift += 1;
auto val = lower_word_first(ws...); // just for debugging purposes split into val
auto res = val | word << (shift - 1) * 8U;
shift -= 1;
return res;
}
#include <cstddef>
#include <utility>
template <std::size_t... Is, typename... Ws>
constexpr auto lower_word_first(std::index_sequence<Is...>, Ws... ws)
{
return ((ws << Is*8) | ...);
}
template <typename... Ws>
constexpr auto lower_word_first(Ws... ws)
{
return lower_word_first(std::index_sequence_for<Ws...>{}, ws...);
}
在这里,std::index_sequence_for
,例如
std::index_sequence_for<A, B, C, D>
产生:
std::index_sequence<0, 1, 2, 3>
然后折叠表达式变成:
(ws_0 << 0*8) | (ws_1 << 1*8) | (ws_2 << 2*8) | (ws_3 << 3*8)
或者,将参数存储在数组中,然后反向迭代。
具有一些 c++20 功能,以及一个强制特定类型的辅助函数,它看起来像:
#include <cstdint>
#include <array>
#include <ranges>
#include <concepts>
template <typename T>
auto type()
{
if constexpr (std::is_same_v<T, std::uint8_t>) return std::uint16_t{};
if constexpr (std::is_same_v<T, std::uint16_t>) return std::uint32_t{};
if constexpr (std::is_same_v<T, std::uint32_t>) return std::uint64_t{};
}
template <std::integral W>
constexpr auto lower_word_first(W w, std::same_as<W> auto... ws)
{
decltype(type<W>()) val{};
const std::array a = { w, ws... };
for (auto v : std::ranges::reverse_view{ a }) {
val <<= 8;
val |= v;
}
return val;
}