这是在Visual Studio 2010上,使用Boost v1.48.0。我正在尝试使用一些结构和共享指向结构的boost :: variant来匹配boost :: static_visitor的正确成员,但没有成功......
对于我的问题,让我们建立这个前提,作为一个例子:
struct t_type_A { int key; foo value; };
struct t_type_B { int key; bar value; };
struct t_type_C { int key; baz value; };
struct t_type_D { int key; qux value; };
bool operator<(const t_type_A &, const t_type_A &);
bool operator<(const t_type_B &, const t_type_B &);
bool operator<(const t_type_C &, const t_type_C &);
bool operator<(const t_type_D &, const t_type_D &);
bool operator==(const t_type_A &, const t_type_A &);
bool operator==(const t_type_B &, const t_type_B &);
bool operator==(const t_type_C &, const t_type_C &);
bool operator==(const t_type_D &, const t_type_D &);
typedef std::shared_ptr<t_type_C> t_shared_C;
typedef std::shared_ptr<t_type_D> t_shared_D;
typedef boost::variant<t_type_A, t_type_B, t_shared_C, t_shared_D> t_variant;
我有一位访客如下:
class variant_less : public boost::static_visitor<bool>
{
public:
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left.value < right.value || (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<T> &right) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
template<typename T, typename U>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<U> &right) const
{
return left->key < right->key;
}
};
实际上,当我将访问者应用于我的变体时,我得到编译器错误:
编辑:我不得不再次查看错误消息。我误解了这个例子,它不是抱怨'价值'而是'钥匙'。错误在下面修复。
错误C2039:'key':不是'std :: tr1 :: shared_ptr&lt; _Ty&gt;'
的成员编译器正在解析两个t_shared_C或两个t_shared_D之间的比较:
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
最合适。这显然不是我想要的。或者,基于我对SFINAE的不稳定知识,我尝试了以下内容:
class variant_less : public boost::static_visitor<bool>
{
public:
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left.value < right.value || (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const T &left, const T &right) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
template<typename T, typename U>
result_type operator()(const T &left, const U &right) const
{
return left->key < right->key;
}
};
我做错了什么?我不想放弃并为每个组合写入重载。
编辑:以下是如何调用它:
typedef boost::multi_index::multi_index_container<
t_variant_vector,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<variant_extractor<1234>, variant_less>
, boost::multi_index::ordered_non_unique<variant_extractor<5678>, variant_less>
// arbitrarily more indexes go here
>
> t_variant_multi_index;
向量是变体的排序向量,按键排序。索引由具有特定“键”值的变体的存在索引。 variant_extractor使用匹配键查找并提取变量。作为一个关于mult_index当时正在做什么的简要介绍,“关键提取器”(一个变体)的结果随后被用作“比较谓词”(variant_less)的参数,用于对该索引进行排序。
答案 0 :(得分:3)
问题在于apply_visitor
必须为变体的所有组合实例化MultiVisitor的operator()
&#39; contents:运行时决定调用哪个函数(因为变量内容的类型只在运行时知道)。
因此,MultiVisitor必须支持所有参数组合。这包括组合,其中一个参数是shared_ptr
但另一个参数不是。
这是一个简单解压缩所有shared_ptr
的解决方案。这也消除了代码重复。
class variant_less : public boost::static_visitor<bool>
{
private:
template<typename T>
result_type impl(const T &left, const T &right) const
{
return left.value < right.value
|| (left.value == right.value && left.key < right.key);
}
template<typename T, typename U>
result_type impl(const T &left, const U &right) const
{
return left.key < right.key;
}
template<typename T>
static T const& unpack(T const& p)
{
return p;
}
template<typename T>
static T const& unpack(std::shared_ptr<T> const& p)
{
return *p;
}
public:
template<typename T, typename U>
result_type operator()(const T& left, const U& right) const
{
return impl(unpack(left), unpack(right));
}
};
答案 1 :(得分:1)
这与模板实例化有关。在编译时,T和shared_ptr都被认为是某种类型,并且编译器不区分普通类型或share_ptr类型,因此编译器将找到第一个匹配的模板函数定义来实例化函数,这就是您的错误发生的方式。
您可以执行与std traits类似的操作:提供两种标记类型:
struct plain_type_tag{};
struct shareptr_type_tag{};
然后将您的功能更改为:
template<typename T, typename U>
result_type operator()(const T &left, const U &right, plain_type_tag) const
{
return left.key < right.key;
}
template<typename T>
result_type operator()(const std::shared_ptr<T> &left, const std::shared_ptr<T> &right, shareptr_type_tag) const
{
return left->value < right->value || (left->value == right->value && left->key < right->key);
}
供你参考: