future_errorの調査

cpprefjpでfuture関係を書いてるのでその検証。
たとえば、std::promiseに対して2回以上値を書き込むと、std::future_error例外が投げられます。

#include <iostream>
#include <future>
#include <thread>
#include <functional>

void foo(std::promise<int>& p)
{
    p.set_value(3);

    try {
        p.set_value(1);
    }
    catch (std::future_error& e) {
        std::cout << e.code().message() << std::endl;
    }
}

int main()
{
    std::promise<int> p;
    std::future<int> f = p.get_future();

    std::thread t(foo, std::ref(p));

    std::cout << f.get() << std::endl;

    t.join();
}
3
Promise already satisfied

std::future_errorクラスはstd::logic_errorを継承した例外クラスですが、std::system_errorと同じようにstd::error_codeを扱います。

namespace std {
  class future_error : public logic_error {
  public:
    future_error(error_code ec);

    const error_code& code() const noexcept;
    const char* what() const noexcept;
  };
}

std::future_errorのエラー値はstd::future_errcというenum classです。

namespace std {
  enum class future_errc {
    broken_promise,
    future_already_retrieved,
    promise_already_satisfied,
    no_state
  };
}

これをstd::error_codeで扱うために、std::future_category()関数が用意されています。

namespace std {
  const error_category& future_category() noexcept;
}

この関数で返されるstd::error_categoryオブジェクトが、std::future_errcのエラー値に対応するエラーメッセージを管理します。
std::error_codeには、std::future_errcの値とstd::future_category()をセットで渡して使います(自分で使うことはないはず)。

#include <iostream>
#include <future>

int main()
{
    std::error_code ec = {
        static_cast<int>(std::future_errc::promise_already_satisfied),
        std::future_category()
    };

    std::cout << ec.message() << std::endl;
}
Promise already satisfied

毎回std::future_category()を設定しなくていいように、std::make_error_code()関数にstd::future_errcのためのオーバーロードが用意されています。

namespace std {
  error_code make_error_code(future_errc e) noexcept;
}
#include <iostream>
#include <future>

int main()
{
    std::error_code ec =
            std::make_error_code(std::future_errc::promise_already_satisfied);

    std::cout << ec.message() << std::endl;
}
Promise already satisfied

以上です。


std::error_codeで自分用のエラー情報を扱う場合のいい拡張例ですね。