以下程序中止:
#include <boost/variant.hpp>
using variant_type = boost::variant< int&, std::string& >;
int main () {
int a, b;
variant_type v (a), u (b);
v == u;
return 0;
}
使用:
$ g++ -std=c++14 t.cpp && ./a.out
a.out: /opt/boost/default/include/boost/variant/detail/forced_return.hpp:39: T boost::detail::variant::forced_return() [with T = const int&]: Assertion `false' failed.
Aborted (core dumped)
AFAICT你无法比较非const引用变体之间的相等性,因为在known_get类中选择了运算符函数调用的错误重载。 known_get在比较器访问者中为const T实例化,而不是看起来应该是T(在v1.59.0中的variant.hpp:905)。
我错过了什么吗?
答案 0 :(得分:3)
我认为这是一个Boost错误。
这里的type requirements是:
- CopyConstructible或MoveConstructible。
- Destructor坚持无抛出异常安全保证。
- 在变体模板实例化时完成。 (有关接受不完整类型以启用递归变体类型的类型包装器,请参阅
boost::recursive_wrapper<T>
。)
以及:
- EqualityComparable:
variant
本身就是EqualityComparable,当且仅当它的每个有界类型都符合概念的要求时。
引用类型是可复制构造的,是无抛出的可破坏的,完整的,并且具有可比性。所以我们在那里的所有要点都很好。问题是实施中使用的访问者是:
template <typename T>
bool operator()(const T& rhs_content) const
{
// Since the precondition ensures lhs and rhs types are same, get T...
known_get<const T> getter;
const T& lhs_content = lhs_.apply_visitor(getter);
// ...and compare lhs and rhs contents:
return Comp()(lhs_content, rhs_content);
}
也就是说,我们使用const T
作为已知的getter。这适用于非引用类型,但对于引用类型不正确,因为known_get
断言如果它的类型错误:
T& operator()(T& operand) const BOOST_NOEXCEPT
{
return operand;
}
template <typename U>
T& operator()(U& ) const
{
// logical error to be here: see precondition above
BOOST_ASSERT(false);
return ::boost::detail::variant::forced_return<T&>();
}
使用int&
,这些重载变为:
const int& operator()(const int& ) const;
const int& operator()(int& ) const; [ U = int ]
第二个重载是首选,因为它引用的类型将比非模板重载更少const限定。这就是你得到断言的原因,这种行为显然是不正确的。我们应该能够比较参考文献!
更简单的解决方案是从const
中删除comparer
并简单地使用:
template <typename T>
bool operator()(T& rhs_content) const
{
known_get<T> getter;
T& lhs_content = lhs_.apply_visitor(getter);
return Comp()(lhs_content, rhs_content);
}
这适用于引用类型以及const
类型。
答案 1 :(得分:0)
boost :: variant的概要不显示为变量定义的运算符==。
这使我建议通过二元访问者进行比较的正确方法。
这是你的(修改过的)代码,它在我的机器上编译(apple clang)你的代码也崩溃了我的编译器。
#include <string>
#include <boost/variant.hpp>
using variant_type = boost::variant< int&, std::string& >;
struct is_equal
{
// compare int with int
bool operator()(const int& l, const int& r) const {
return l == r;
}
// compare string with string
bool operator()(const std::string& l, const std::string& r) const {
return l == r;
}
// anything else compared with anything else compares false.
template<class X, class Y>
bool operator()(const X&, const Y&) const {
return false;
}
};
int main () {
int a = 0, b = 0;
variant_type v = a, u = b;
bool ok = boost::apply_visitor(is_equal(), v, u);
// bool ok = (v == u);
return 0;
}