読者です 読者をやめる 読者になる 読者になる

ボレロ村上 - ENiyGmaA Code

中3女子です。

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 はディープコピーが行われます。

要件


もちろんイテレータやコンテナは、constexpr として使えるクラスである必要があります。
なので、std::vector などは使えません。
std::array も、必要なメンバ関数が constexpr でないため使えません。


sprout::array や sprout::basic_string は対応しています。
CEL の sscrisk::cel::array も使うことが出来ます。