constexpr
コンパイラの拡張機能に頼らずに、整数のエンディアンを入れ替える機能を書くにはどうすればいいですか?整数のエンディアンを変更するためのconstexprスワップ関数の記述方法は?
答えて
はい、かなり簡単です。ここでは、再帰(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);
}
ここで私はアキュムレータとしてj
を使用して、ループカウンタとしてn
(インデックスバイト)よ。
あなたがC++17 fold expressionsをサポートするコンパイラを持っている場合、それはあなたが手で書きたい正確に何に出て展開する何かを書くことが可能です:
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)>{});
}
この形式の利点は、それが使用されていないので、ということですループや再帰を使用すると、最適なアセンブリ出力を得ることができます.X86-64では、clangはwork out to use the bswap
instructionまで管理します。
私は、bswapがコンパイラによって検出されない場合(O(log(n))対O(N))、潜在的により良いパフォーマンスを持つ次の解決策を提案します。 Nは、これはまだ、おそらく無関係であり、通常は= 8 <であることを考える:このフォームはecatmurのソリューションよりも複雑であるため
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value,T>::type
constexpr alternating_bitmask(const size_t step){
T mask(0);
for (size_t i=0;i<digits<T>();i+=2*step){
mask|=(~T(0)>>(digits<T>()-step))<<i;
}
return mask;
}
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value,T>::type
constexpr bswap(T n){
for (size_t i=digits<unsigned char>();i<digits<T>();i*=2){
n = ((n&(~(alternating_bitmask<T>(i))))>>i)|
((n&((alternating_bitmask<T>(i))))<<i);
}
return n;
}
コンパイラは難しい仕事の最適化を持っていますが、打ち鳴らすは、まだ我々はBSWAPを意味していることを知ります。
内側ループ(カウント最適化ではない)がΘ(N/logN)(アウターループの反復ごとに)の償却された複雑さを有するため、この解は実際にはΘ(N)の時間複雑さも有する。実際のΘ(log N)を得るためには、ビットマスクをメモする必要がある。配列にあらかじめ計算されています。 –
@ArneVogelこれは当てはまりますが、私はビットマスクを生成する関数がconstexprであるため、ビットマスクは時定数をコンパイルすると仮定しました。 – Lykos
- 1. saveTable関数の記述方法は?
- 2. edeのロケート関数の記述方法
- 3. 複数のC関数を内部的に呼び出すためのC++テンプレート関数の記述方法?
- 4. パンダのチャンクで関数を記述する方法は?
- 5. Pythonでの整数エンディアン
- 6. ローカルストレージデータを更新するためのjavascriptコードの記述方法
- 7. window.resize関数の記述方法に関するアドバイス?
- 8. ジェネリックキャスト関数の記述Scala
- 9. ログファイルを作成してPythonで記述するためのクラスまたは関数の作成方法は?
- 10. PL/SQL関数の記述方法は、最大関数に似ています
- 11. このpl/pgsql関数の記述方法は?
- 12. C++タプルのfold/sum関数の記述方法は?
- 13. 循環グラフノードのhashCode()関数の記述方法は?
- 14. data.tableを呼び出す関数を呼び出す関数の記述方法?
- 15. 、それは整数のエンディアン普遍的な実装方法
- 16. 渡された無名関数のパラメータを記述する方法は?
- 17. C#コードでJavaScript関数を記述する方法は?
- 18. Haskell Pipes "sum"関数の記述方法は?
- 19. 2つのカテゴリ変数間の関係を記述する
- 20. Stringプロトタイプを変更したインライン関数用にJSDocを正しく記述する方法は?
- 21. PEG文法における関数の引数の記述方法
- 22. constexprメンバ関数を使用したconstexprメンバ変数の初期化
- 23. 私はJavaScriptで関数fを記述するために任務いjavascriptの
- 24. mkdocsでの関数構文の記述方法
- 25. Linuxシェルスクリプト用のDB2関数の記述方法
- 26. Python __del__関数のユニットテストケースの記述方法
- 27. 一般的なstd :: vector push_backのテンプレート関数の記述方法?
- 28. 複数の引数を1行に記述する方法
- 29. メソッドの可変引数のテストケースの記述方法
- 30. スワップ「エンディアン」と私はfloatとdouble値の「エンディアン」を切り替えるしたい
「整数のエンディアン」とは何ですか? 15のエンディアンは何ですか? –
@KerrekSBそれは何でも。私はその質問をしなかった。私の質問はビッグエンディアンをリトルエンディアンにスワップする方法、そしてその逆の方法です。 – user1095108
@KerrekSB:C++(一般的なほとんどのプログラミング)の文脈では、整数と言うとき、通常は整数オブジェクトを参照します。つまり、整数データを格納するために使用されるメモリ内の領域で、通常は基本整数型(char、short、int、longおよびlong long、およびそれらの符号なしバリアント)の1つです。あなたは本当にその使用法を見いだすことはありませんか? –