Vicenteさんが標準向けに提案していた関数を元に、boost::optional
用のパターンマッチ関数を作ってみました。
- 実装
- コード例
- テスト
インタフェース:
// shand/match.hpp namespace shand { // 1引数版 template <class T, class F> void match(boost::optional<T>& x, F f); template <class T, class F> void match(const boost::optional<T>& x, F f); // 2引数版 template <class T, class F1, class F2> void match(boost::optional<T>& x, F1 f1, F2 f2); template <class T, class F1, class F2> void match(const boost::optional<T>& x, F1 f1, F2 f2); }
関数の型F
、F1
、F2
は、以下のいずれかのシグニチャを持たせます:
R(T&)
:optional
オブジェクトが有効な値を持っていれば呼ばれるR()
:optional
オブジェクトが無効な値なら呼ばれる
使用例:
#include <iostream> #include <boost/optional.hpp> #include <shand/match.hpp> int main() { boost::optional<int> a = 3; shand::match(a, [](int& x) { // 有効な値を持っていれば呼ばれる std::cout << x << std::endl; }); boost::optional<int> b; shand::match(b, [] { // 無効な値なら呼ばれる std::cout << "none" << std::endl; }); shand::match(a, // 有効な場合と無効な場合で関数を呼び分ける [](int& x) { std::cout << x << std::endl; }, [] { std::cout << "none" << std::endl; } ); }
出力:
3 none 3
この関数は、「optional
オブジェクトが有効な状態かどうか判定してから中身を取り出す」という二段階の処理を同時に行い、「じつは無効な状態なのに中身を取り出そうとした」というミスを防ぐために使用します。
expected
のmap()
メンバ関数のようなものです。
実装技術の話
関数から引数の型を取り出して「有効な値用の関数か、無効の値用の関数か」を判定するのではなく、関数が特定のシグニチャで呼び出し可能かを調べるis_callable
メタ関数を使用して、判定しています。
is_callable<F, T&>::value == true
(F
がT&
型を受け取って呼び出し可能な関数か、が真)なら有効な値用の関数と見なしています。
is_callable<F>::value == true
(引数なし)で無効な値用の関数と見なしています。