読者です 読者をやめる 読者になる 読者になる

optional はコンテナか?

C++ に提案されている機能の内で optional という型がある。 従来は何らかの値を返す関数が失敗した場合にその値がポインタならヌルポインタを、整数なら -1 を返すなどといった「無効値」を使っていたわけだが、正常な値としてヌルポインタや -1 を返す可能性がある関数では別の方法が必要であるし、何より無効であることを確認する方法が一貫していないのはうんざりする。 そういった問題を解決するのが optional である。

optional はまだ仕様に入ったわけではないのだが、 Boost::optional を基礎にした提案であり、 Boost ユーザの中には積極的に使っている人もいるようだ。 最近の MinGW を導入していれば std::experimental::optional という名前で入っている。 公式に提案されている optionalBoost::optional は仕様が異なるので注意を要する。

さて、この optional であるが、 0 個または 1 個の値を入れられるコンテナであるという解釈があるようだ。 他の言語ではそういう解釈を持つものもあるらしい。

私は最近の C++ 事情をあまり追っていないので久々に少し遊んでみようと std::experimental::optionalイテレータを定義してみた。

// optional_iterator.h

template<class T>
class optional_iterator {
private:
  std::experimental::optional<T>* object;
public:
  optional_iterator& operator++(void) {
    return object==nullptr ? *this : (object=nullptr, *this);
  }
  optional_iterator operator++(int) {
    optional_iterator<T> temp = *this;
    this->object = nullptr;
    return optional_iterator<T>(temp);
  }
  optional_iterator(std::experimental::optional<T>& o)
    : object(o==std::experimental::nullopt ? nullptr : &o) {
  }
  optional_iterator() : object(nullptr) {
  }
  bool operator==(optional_iterator x) {
    return object == x.object;
  }
  bool operator!=(optional_iterator x) {
    return !(object == x.object);
  }
  T operator*(void) {
    return object ? **object : T();
  }
};

namespace std {
  template<class T>
  optional_iterator<T> begin(std::experimental::optional<T>& opt) {
    return optional_iterator<T>(opt);
  }

  template<class T>
  optional_iterator<T> end(std::experimental::optional<T>& opt) {
    return optional_iterator<T>();
  }
}

以下のような要領で使える。

#include <experimental/optional>
#include <iterator>
#include <iostream>
#include "optional_iterator.h"

int main(void) {
  std::experimental::optional<int> o1=1;
  for(auto i :o1) std::cout << i <<std::endl; // 1 が表示される
  std::experimental::optional<int> o2;
  for(auto i :o2) std::cout << i <<std::endl; // 表示されない
}

Document ID: 6d8f20d090b1289ff2a744aaa2f04e55