C++向けライブラリboostにあるboost::optionalは、
値がない状態(初期化すらされていない状態)を表現できる仕組みです。
例題では、
double sqrt(double n );
で、n < 0のときは戻り値がないことを示すために、
boost::optional<double> sqrt(double n);
とする例が挙げられています。
ちなみに、使う側は、(あたかもポインタのように)値があるかをチェックして、その後使う、という風にします。
boost::optional<double> value = sqrt(なにか計算式);
if (value) {
std::cout << "答え: " << *value << std::endl;
} else {
std::cout << "解なし" << std::endl;
}
boost::optionalの例題はネットで見る限り、なぜか関数の戻り値の例ばかりです。
が、実際に使ってみると、なかなかどうして、boost::optionalはちょっとした
ループでも便利に使えることがわかります。
たとえば、繰り返しの直前の値を保持する例。
template<typename IterT, typename ValueT>
void print_unique_values_in_sorted_sequence(IterT begin, IterrT end)
{
boost::optional<ValueT> lastValue;
for (IteratorType i = begin; i != end; ++i) {
if (! (lastValue && *i == *lastValue))
std::cout << *i << std::endl;
lastValue = *i;
}
}
あるいは、条件を満たすものが見つかったときに、その値を保持する例。
boost::optional<size_t> smallGapIndex;
boost::optional<size_t> largeGapIndex;
for (size_t i = 0; i + 1 < ary.size(); ++i) {
double diff = fabs(ary[i + 1] - ary[i]);
if (! smallGapIndex && diff < 0.0001)
smallGapIndex = i;
if (! largeGapIndex && diff > 1000.0)
largeGapIndex = i;
if (smallGapIndex && largeGapIndex)
break; // for i
}
if (smallGapIndex)
std::cout << "small gap index = " << *smallGapIndex << std::endl;
if (largeGapIndex)
std::cout << "large gap index = " << *largeGapIndex << std::endl;
公開するAPIにboostの文字を入れるのは禁止されているときでも、
こういうこそっとした使い方ならお目こぼしになる可能性もありますし。
おすすめです。
(最初、boost::optionalの実装って、本当はポインタを持ってヒープを
割り当ててるんじゃないかと疑いつつ、optional.hppを見たのですが、
いやもう、とても鍛えられたコードでした。疑ってごめんなさい)
値がない状態(初期化すらされていない状態)を表現できる仕組みです。
例題では、
double sqrt(double n );
で、n < 0のときは戻り値がないことを示すために、
boost::optional<double> sqrt(double n);
とする例が挙げられています。
ちなみに、使う側は、(あたかもポインタのように)値があるかをチェックして、その後使う、という風にします。
boost::optional<double> value = sqrt(なにか計算式);
if (value) {
std::cout << "答え: " << *value << std::endl;
} else {
std::cout << "解なし" << std::endl;
}
boost::optionalの例題はネットで見る限り、なぜか関数の戻り値の例ばかりです。
が、実際に使ってみると、なかなかどうして、boost::optionalはちょっとした
ループでも便利に使えることがわかります。
たとえば、繰り返しの直前の値を保持する例。
template<typename IterT, typename ValueT>
void print_unique_values_in_sorted_sequence(IterT begin, IterrT end)
{
boost::optional<ValueT> lastValue;
for (IteratorType i = begin; i != end; ++i) {
if (! (lastValue && *i == *lastValue))
std::cout << *i << std::endl;
lastValue = *i;
}
}
あるいは、条件を満たすものが見つかったときに、その値を保持する例。
boost::optional<size_t> smallGapIndex;
boost::optional<size_t> largeGapIndex;
for (size_t i = 0; i + 1 < ary.size(); ++i) {
double diff = fabs(ary[i + 1] - ary[i]);
if (! smallGapIndex && diff < 0.0001)
smallGapIndex = i;
if (! largeGapIndex && diff > 1000.0)
largeGapIndex = i;
if (smallGapIndex && largeGapIndex)
break; // for i
}
if (smallGapIndex)
std::cout << "small gap index = " << *smallGapIndex << std::endl;
if (largeGapIndex)
std::cout << "large gap index = " << *largeGapIndex << std::endl;
公開するAPIにboostの文字を入れるのは禁止されているときでも、
こういうこそっとした使い方ならお目こぼしになる可能性もありますし。
おすすめです。
(最初、boost::optionalの実装って、本当はポインタを持ってヒープを
割り当ててるんじゃないかと疑いつつ、optional.hppを見たのですが、
いやもう、とても鍛えられたコードでした。疑ってごめんなさい)