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

special_value

C++

整数 + 特殊な値を表現する型

これをクラステンプレート化した。

インタフェース:

namespace shand {
  template <class ValueType, class Enum>
  class special_value {
  public:
    using value_type = ValueType;
    using enum_type = Enum;

    special_value(); // initialize ValueType
    special_value(ValueType value);
    special_value(Enum e);

    special_value& operator=(ValueType value);
    special_value& operator=(Enum e);

    // どちらの値が入っているかの判定
    bool has_value() const;
    bool has_enum() const;

    // 値の取り出し
    // それぞれの型の値が入っていない場合は、boost::bad_get例外を送出する
    ValueType& get_value();
    const ValueType& get_value() const;
    Enum& get_enum();
    const Enum& get_enum() const;

    // それぞれの型の値が入っていたときに指定された関数オブジェクトを呼び出す。
    // 入っていなかったら関数オブジェクトを呼び出さない。
    // *thisを返す。
    template <class F> // void(ValueType& value) or void(ValueType& value)
    special_value& on_value(F f);
    template <class F>
    const special_value& on_value(F f) const;

    template <class F> // void(Enum value) or void(Enum& value)
    special_value& on_enum(F f);
    template <class F>
    const special_value& on_enum(F f) const;
  };
}

例:

#include <iostream>
#include <shand/special_value.hpp>

enum class PopType { Root };
std::string popToString(PopType) { return "Root"; }

int main()
{
    // size_tかPopTypeのどちらかの型の値が入る
    shand::special_value<std::size_t, PopType> pop_count = 1u;
//  pop_count = PopType::Root;

    // size_tの値が入っていたときの処理
    pop_count.on_value([](std::size_t value) {
        std::cout << value << std::endl;
    })
    // PopTypeの値が入っていたときの処理
    .on_enum([](PopType pop) {
        std::cout << popToString(pop) << std::endl;
    });
}

出力:

1

実装はboost::variantのラッパー。設計は、expectedを参考にした。クラス名はこれでいいのか、まだ悩み中。もしかしたら変えるかも。