如何制作boost :: variant的简化版本?

时间:2012-04-03 03:07:18

标签: c++ templates c++11 void variant

我有一套更为简单的要求,并且不需要太多的变种机器。如果我能帮助它,我也不想依靠提升。

我需要存储编译时已知的任意类型(可能是void)。它可以是可构造的,也可以是可构造的,如果其中任何一个抛出,则允许包含的值未定义。

它可能还包含::std::exception_ptr::std::error_code,而不是此值。

如果允许::boost::variant<T, ::std::exception_ptr, ::std::error_code>无效,则

T会起作用。除了::boost::variant提供“永不空”的保证&#39;在这种情况下我实际上并不需要。而且,如果我理解它是如何正常工作的,那么它与可以移动但不能复制的类型不太兼容。

现在我写了很多重复的代码,我不应该写这些代码来分别处理这些类型。我还存储了每种类型的对象的副本,并标记了相关的值。最后,void给出了整个系统的一致性,并要求我在整个地方编写专业化。

有更好的方法吗?

这是我所拥有的简化示例。这基本上是一个类,用于保存结果以传输到另一个线程,有点像未来:

template <typename ResultType>
class stored_result {
 public:
   stored_result() : is_val_(false), is_err_(false), is_exception_(false) { }

   void set_bad_result(::std::error err) {
      is_err_ = true;
      error_ = ::std::move(err);
   }
   void set_bad_result(::std::exception_ptr exception) {
      is_exception_ = true;
      exception_ = ::std::move(exception);
   }
   void set_result(ResultType res) {
      is_val_ = true;
      val_ = ::std::move(res);
   }

   ResultType result() {
      if (is_val_) {
         is_val_ = false;
         return ::std::move(val_);
      } else if (is_exception_) {
         is_exception_ = false;
         ::std::rethrow_exception(::std::move(exception_));
      } else if (is_error_) {
         is_error_ = false;
         throw ::std::system_error(error_);
      } else {
         throw ::std::runtime_error("Asked for result when there was none.");
      }
   }

 private:
   bool is_val_, is_err_, is_exception_;
   T val_;
   ::std::exception_ptr exception_;
   ::std::error_code error_;
};

2 个答案:

答案 0 :(得分:2)

[编辑:问题已经编辑,在我写完之后添加了示例代码]。

出现你所追求的是一种从函数返回有效结果(任意类型)的方法,或指示失败的东西。

如果是这样,那么下面的代码就可以很好地解决你的问题,即返回任意类型结果的部分(这个类类似于boost::optional,而这个类基于Barton和Nackman的{ {1}}类)。

对于错误指示,只需将布尔值替换为错误信息,并将概念性“无”替换为概念性“失败”:

Fallible

答案 1 :(得分:2)

如何使用您现在拥有的代码以透明的方式处理void的示例:

struct empty_type {};

template<typename T>
using Store = typename std::conditional<std::is_void<T>::value, empty_type, T>::type;

template<typename T>
T&&
restore(T&& t)
{
    return std::forward<T>(t);
}

void
restore(empty_type)
{}

template <typename ResultType>
class stored_result {
public:
    // snipped everything that is left unchanged

    template<
        typename U = ResultType
        , typename std::enable_if<
            !std::is_void<U>::value
            , int
        >::type = 0
    >          
    void set_result(U res) {
        is_val_ = true;
        val_ = std::move(res);
    }

    template<
        typename U = ResultType
        , typename std::enable_if<
            std::is_void<U>::value
            , int
        >::type = 0
    >          
    void set_result() {
        is_val_ = true;
    }

    ResultType result() {
        if (is_val_) {
            is_val_ = false;
            return restore(std::move(val_));
        } else if {
            // rest as before
    }

private:
    Store<T> val_;
};

虽然代码未经测试可能会有一些问题。