std::experimental::optional
モチベーション
ついにoptionalが標準ライブラリに来て嬉しかったので。
optional
C++17にはoptionalが追加されるようです。 optionalを使うと以下のような処理が改善されます。
取得に失敗する関数を書く時どうしますか?
#include<iostream> struct Foo { Foo()=default; std::string message_; }; // こう書きたいけど Foo* Get(bool flag){ // fooはローカルオブジェクトなので Foo foo; foo.message_ = "ok"; if(flag){ // 返したら不定値のポインタになってしまう return &foo; } else{ return nullptr; } } // 仕方ないのでこうしよう bool Get(bool flag, Foo *foo){ foo->message_ = "ok"; if(flag){ // このパスを通ったらオブジェクトが生成されると分かりにくい return true; } else{ // こちらも、このパスを通ったら無効だと分かりにくい return false; } } int main(){ // 宣言と初期化が同時ではない Foo foo; // 取得と有効無効の役割が混ざっている if(Get(true, &foo)){ std::cout << "1:" << foo.message_ << std::endl; } if(Get(false, &foo)){ std::cout << "2:" << foo.message_ << std::endl; } }
optionalを使うと以下の様に書けます。
#include<experimental/optional> #include<iostream> struct Foo { Foo()=default; std::string message_; }; // 戻り値が明確(値か無効値) std::experimental::optional<Foo> Get(bool flag){ Foo foo; foo.message_ = "ok"; if(flag){ // こちらが値を返すパスだと明確に分かる return foo; } else{ return std::experimental::nullopt; } } int main(){ // 宣言と同時に初期化できる(autoが使える) auto foo = Get(true); // 有効か無効かの真偽値で判断できる if(foo){ std::cout << "1:" << foo->message_ << std::endl; } foo = Get(false); if(foo){ std::cout << "2:" << foo->message_ << std::endl; } }
まだまだstd::experimental::optionalが使える環境では作業できないかもしれませんが boost::optionalという選択肢もあります。