提升引用变体和相等比较

时间:2015-10-23 17:08:53

标签: c++ boost boost-variant

以下程序中止:

#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)。

我错过了什么吗?

2 个答案:

答案 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;
}