【发布时间】:2015-05-29 23:51:37
【问题描述】:
我正在尝试将 boost::variant 与模板类型一起使用。例如,我有一个模板类型Tag<T>,boost::variant AnyTag 包含Tag<double>、Tag<int> 和Tag<std::string> 等类型。每个Tag<T> 都有类型为 T 的成员。
现在,我想将这些变体放在一个容器中,并在运行时简单地赋值,例如,
for(AnyTag & tag: AllTags) {
setValue(tag, getValueFromXml());
}
函数setValue(AnyTag &tag, T &val) 必须使用AnyTag 标记的运行时类型才能正确地为标记分配正确的值。
我的解决问题的尝试可以在下面找到,它使用了另一个变体,其中仅包括可以在 AnyTag (TagValueType) 中使用的可能的 T 类型。
template<typename T, typename = void>
class Tag {};
template <typename T>
class Tag<T, EnableIf<std::is_arithmetic<T>>> {
public:
T value = 0;
std::string address = "";
T maxValue = std::numeric_limits<T>::max();
typedef T value_type;
};
template <typename T>
class Tag<T, DisableIf<std::is_arithmetic<T>>> {
public:
T value;
std::string address = "";
typedef T value_type;
};
typedef boost::variant<Tag<std::string>,
Tag<double>,
Tag<int>,
> AnyTag;
typedef boost::variant<std::string, double, int> TagValueType;
class tag_set_value_visitor: public boost::static_visitor<void>
{
const TagValueType & value;
public:
tag_set_value_visitor(const TagValueType & val): value(val){}
template <typename T>
void operator()(T & tag) const
{
tag.value = boost::get<typename T::value_type>(value);
}
};
inline void setValue(AnyTag & tag, const TagValueType & val) {
assert(tag.which() == val.which());
boost::apply_visitor( tag_set_value_visitor(val), tag );
}
不幸的是,这种方法不是我想要的,因为例如在编译期间,如果我执行以下操作没有问题:
AnyTag a = Tag<int>();
setValue(a, double(1.3));
但在运行时,boost 库会检测到类型不匹配并导致程序崩溃。
所以,我的解决方案是一种类型擦除,只是推迟了问题。
我想要的是一个 setValue(AnyTag &tag, T &val),其中 T 是 AnyTag 的运行时类型。
我知道这就是变体的访问者试图做的事情,但是在这种情况下存在一个问题,因为当我们构造访问者时,我们必须知道我们将要使用的类型。
对这个问题有什么想法或想法吗?
P.S.:很抱歉这篇文章很长,但我找不到用更少的词来解释我的思维过程的方法。
【问题讨论】:
-
在
setValue(a, double(1.3))中,当问题是a的run-time 类型时,您希望编译器如何检测问题? -
尼莫,我没有。我在某处写道,我正在做的只是推迟问题。我想要的是(在“宽松”语法中):1)编译器生成 setValue(AnyTag::Tag
&, int &val) setValue(AnyTag::Tag &, double &val) 2)然后在运行时多态地根据 AnyTag 的运行时类型选择正确的 setValue(...)。 -
我知道在 C++ 中调度不能以这种方式发生,所以我想也许有人知道一个可以解决这个问题的技巧(使用访问者模式)。