Sprout.Algorithm - constexpr mutating operations アルゴリズム入門
以前も書きましたが、Sprout C++ Library は固定長コンテナに対する STL ライクな変更のアルゴリズムを提供します。
Github https://github.com/bolero-MURAKAMI/Sprout
もちろん constexpr では代入操作が出来ないので、インタフェースなどは STL とは異なっています。
ここでは、まず手はじめに copy アルゴリズムを例にとって、
Sprout の constexpr アルゴリズムの使い方を示そうと思います。
sprout::copy
-
- sprout::copy の宣言
template<typename InputIterator, typename Result> SPROUT_CONSTEXPR inline typename sprout::fixed::result_of::algorithm<Result>::type copy( InputIterator first, InputIterator last, Result const& result );
入力は std::copy と同じくイテレータの組です。
第3引数は、std::copy ならば OutputIterator を渡しますが、sprout::copy は出力先となるコンテナそのものを渡します。
また返値は、「出力先コンテナの先頭へ入力をコピーした結果と等価なコンテナ」を返します。
#include <sprout/algorithm/copy.hpp> #include <sprout/array.hpp> #include <sprout/fixed_container.hpp> // for begin, end int main() { using namespace sprout; static constexpr auto arr1 = array<int, 10>{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; static constexpr auto arr2 = array<int, 10>{}; static constexpr auto copied = sprout::copy( sprout::begin(arr1) + 2, sprout::begin(arr1) + 8, arr2 ); // // ↓入力範囲 // arr1: 1 2 [3 4 5 6 7 8] 9 10 // arr2: [0 0 0 0 0 0 0 0 0 0 0] // ↑出力先 // // equal(copied, {{3, 4, 5, 6, 7, 8, 0, 0, 0, 0}}) // }
ちなみに出力範囲が入力範囲より小さい場合、std::copy では未定義になりますが、
sprout::copy では、入力がはみ出した分は単に無視されます。
#include <sprout/algorithm/copy.hpp> #include <sprout/array.hpp> #include <sprout/fixed_container.hpp> // for begin, end int main() { using namespace sprout; static constexpr auto arr1 = array<int, 10>{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; static constexpr auto arr2 = array<int, 4>{}; static constexpr auto copied = sprout::copy( sprout::begin(arr1) + 2, sprout::begin(arr1) + 8, arr2 ); // // ↓入力範囲 // arr1: 1 2 [3 4 5 6 7 8] 9 10 // arr2: [0 0 0 0] // ↑出力先 // // equal(copied, {{3, 4, 5, 6}}) // }
また、出力先が常に先頭では困る場合があります。
出力先の範囲を制御したい場合、sprout::sub を使います。
なお、GCC4.7 現在でこのコードをコンパイルするには、
SPROUT_CONFIG_SUPPORT_TEMPORARY_CONTAINER_ITERATION を define する必要があります。
#define SPROUT_CONFIG_SUPPORT_TEMPORARY_CONTAINER_ITERATION #include <sprout/algorithm/copy.hpp> #include <sprout/array.hpp> #include <sprout/fixed_container.hpp> // for begin, end, get_fixed, get_fixed_copy #include <sprout/sub_array.hpp> // for sub int main() { using namespace sprout; static constexpr auto arr1 = array<int, 10>{{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}}; static constexpr auto arr2 = array<int, 10>{}; static constexpr auto copied = sprout::copy( sprout::begin(arr1) + 2, sprout::begin(arr1) + 8, sprout::sub(arr2, 2, 8) ); // // ↓入力範囲 // arr1: 1 2 [3 4 5 6 7 8] 9 10 // arr2: 0 0 [0 0 0 0 0 0] 0 0 // ↑出力先 // // equal(copied, {{3, 4, 5, 6, 7, 8}}) // is_same(decltype(copied), sub_array<array<int, 10> > const) // static constexpr auto copied_ = sprout::get_fixed_copy(copied); // // equal(copied_, {{0, 0, 3, 4, 5, 6, 7, 8, 0, 0}}) // is_same(decltype(copied_), array<int, 10> const) // }
sprout::sub(cont, a, b) は、コンテナ cont の begin(cont) + a から begin(cont) + b の範囲を切り出します。
b を省略した場合、begin(cont) + a から end(cont) までの範囲になります。
出力に sub_array を渡した場合、結果も sub_array になります。
結果から、範囲全体を取り出す場合は、sprout::get_fixed または sprout::get_fixed_copy を使います。
get_fixed は参照を返し、get_fixed_copy はディープコピーが行われます。