【发布时间】:2012-04-16 17:07:22
【问题描述】:
我有一套更简单的要求,不需要太多变体的机器。如果我能帮上忙,我也不想依赖 boost。
我需要存储编译时已知的任意类型(可能是void)。它要么是可移动构造的,要么是可复制构造的,如果其中任何一个抛出,则允许包含的值未定义。
除了这个值,它还可以包含::std::exception_ptr 或::std::error_code。
如果T 被允许无效,::boost::variant<T, ::std::exception_ptr, ::std::error_code> 将起作用。除了::boost::variant 提供了我在这种情况下实际上不需要的“永不空保证”。而且,如果我理解它是如何正常工作的,它与可以移动但不能复制的类型不太兼容。
现在我正在编写大量重复的代码,我不应该编写这些代码来分别处理每种类型。我还存储了每种类型和标志值的对象的副本,说明哪些是相关的。最后,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_;
};
【问题讨论】:
-
您可以以对用户透明的方式将
void映射到唯一的空类型。这将允许您重用boost::variant,但不需要专业化帮助。然而,boost::variant最大的障碍是移动构造。 -
听起来很像过早优化。
-
@LucDanton:点头 是的,我在另一个答案中看到了这一点。我想我可以理解它是如何工作的。
-
@Cheersandhth.-Alf:不,这是一个设计级别的问题。我一直在到处写这些重复的代码。由于很多不同的原因,这并不好。
-
我知道如何回答你,但如果你不熟悉它,你最好看看
std::aligned_storage。
标签: c++ templates c++11 void variant