如何编写constexpr swap函数来改变整数的endianess?

use*_*108 20 c++ endianness constexpr c++14 c++17

如何编写一个constexpr函数来交换整数的endianess,而不依赖于编译器扩展,你能举例说明如何做到这一点吗?

eca*_*mur 40

是的,这很容易; 这是一个递归(C++ 11兼容)实现(仅限无符号整数类型):

#include <climits>
#include <cstdint>
#include <type_traits>

template<class T>
constexpr typename std::enable_if<std::is_unsigned<T>::value, T>::type
bswap(T i, T j = 0u, std::size_t n = 0u) {
  return n == sizeof(T) ? j :
    bswap<T>(i >> CHAR_BIT, (j << CHAR_BIT) | (i & (T)(unsigned char)(-1)), n + 1);
}
Run Code Online (Sandbox Code Playgroud)

例.

这里我j用作累加器和n循环计数器(索引字节).

如果您有一个支持C++ 17折叠表达式的编译器,那么可以编写一些扩展到您手写的内容:

template<class T, std::size_t... N>
constexpr T bswap_impl(T i, std::index_sequence<N...>) {
  return ((((i >> (N * CHAR_BIT)) & (T)(unsigned char)(-1)) <<
           ((sizeof(T) - 1 - N) * CHAR_BIT)) | ...);
}; //                                        ^~~~~ fold expression
template<class T, class U = typename std::make_unsigned<T>::type>
constexpr U bswap(T i) {
  return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
}
Run Code Online (Sandbox Code Playgroud)

这种形式的优点是因为它不使用循环或递归,所以你几乎可以保证获得最佳的汇编输出 - 在x86-64上,clang甚至设法使用该bswap指令.

  • 您可能有兴趣知道这个答案是由 cppreference 的折叠表达式文档链接到的(不确定是您自己将它们放在那里还是其他人这样做了)。 (2认同)
  • 不是我,但感谢您指出这一点 - 很高兴有一个不仅仅是总和的例子。 (2认同)
  • 来到这里是因为 cppreference 折叠文档,并且绝对也很欣赏它! (2认同)