Vicenteさんが標準向けに提案していた関数を元に、boost::optional
用のパターンマッチ関数を作ってみました。
インタフェース:
namespace shand {
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);
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
(引数なし)で無効な値用の関数と見なしています。
参照