用于重新排序无符号整数的 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...);
}

DEMO

在这里,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)

或者,将参数存储在数组中,然后反向迭代。

具有一些 功能,以及一个强制特定类型的辅助函数,它看起来像:

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

DEMO 2