動作確認用に作成したコードのメモです。以下のコードではstd::ranges::range<T>
コンセプトを満たす型をレンジあるいはrange<T>
として表記することもあります。
- プロジェクションとは?
- range<optional<int>>の各要素の空判定を出力する。
- range<optional<int>>の無効値を-1に変換して各要素を出力する。
- range<tuple>からstringを抜き出す。
- range<tuple>からタプル内のstring型要素が空のタプルだけコピーしたvector<tuple>を作成する。
プロジェクションとは?
プロジェクションはアルゴリズムがレンジ(Ranges)の各要素に変換や判定のような処理を加える前に呼び出すcallable-type(関数呼び出し演算子を適用できる型)です。クラスや構造体のフィールド、関数の実行と処理を分解して、それぞれを再利用しやすくすることを想定しているそうです。
range<optional<int>>
の各要素の空判定を出力する。
range<optional<int>>
はメンバー関数のポインタ&std::optional<int>::has_value
でプロジェクションできます。プロジェクション結果は空判定結果(bool
)です。
#include <optional> #include <algorithm> #include <iostream> #include <ranges> int main() { std::optional<int> values[]{ 0, 1, std::nullopt, 2, std::nullopt }; auto print_boolalpha = [](bool f) {std::cout << std::boolalpha << f << std::endl; }; std::ranges::for_each(values, print_boolalpha, &std::optional<int>::has_value); // 出力:true, true, false, true, false return 0; }
range<optional<int>>
の無効値を-1
に変換して各要素を出力する。
range<optional<int>>
に対するプロジェクションとしてラムダ式を適用する例です。ここではrangeの要素を引数としたラムダ式value_or_minus_1
の結果が引数を出力する処理関数print
へ渡されます。
#include <optional> #include <algorithm> #include <iostream> #include <ranges> int main() { std::optional<int> values[]{ 0, 1, std::nullopt, 2, std::nullopt }; auto print = [](const int& value) {std::cout << value << std::endl; }; auto value_or_minus_1 = [](const std::optional<int>& value) { return value.value_or(-1); }; std::ranges::for_each(values, print, value_or_minus_1); // 出力: // 0, 1, -1, 2, -1 return 0; }
range<tuple>
からstring
を抜き出す。
std::identity{}
でプロジェクション結果をそのまま返せます。この場合は素直に抜き出したほうが良いかもしれません。
#include <string> #include <tuple> #include <vector> #include <algorithm> #include <iostream> #include <ranges> #include <utility> int main() { std::tuple<int, std::string> tuples[]{ {0, "0"}, {1, "1"}, {2, ""}, {3, "3"}, {4, ""} }; std::vector<std::string> v1; auto get_string = [](const auto& value) { return std::get<std::string>(value); }; std::ranges::transform(tuples, std::back_inserter(v1), std::identity{}, get_string); std::ranges::for_each(v1, [](auto&& value) { std::cout << value << std::endl; }); // 出力:"0", "1", "", "3", "" return 0; }
range<tuple>
からタプル内のstring
型要素が空のタプルだけコピーしたvector<tuple>
を作成する。
std::ranges::copy_if
は判別関数にプロジェクションで取得した値を渡しますが、コピーされる値は渡したタプルそのものであることに注意してください。
#include <string> #include <tuple> #include <vector> #include <algorithm> #include <iostream> #include <ranges> int main() { std::tuple<int, std::string> tuples[]{ {0, "0"}, {1, "1"}, {2, ""}, {3, "3"}, {4, ""} }; std::vector<std::tuple<int, std::string>> v1; auto get_string = [](const auto& value) { return std::get<std::string>(value); }; auto is_string_empty = [](const std::string& s) { return s.empty(); }; std::ranges::copy_if(tuples, std::back_inserter(v1), is_string_empty, get_string); std::ranges::for_each(v1, [](const auto& tuple) { std::cout << "{" << std::get<int>(tuple) << ", \"" << std::get<std::string>(tuple) << "\"}" << std::endl; }); // 出力:{2, ""}, {4, ""} return 0; }