C++ Boost变量引用与等式比较

C++ Boost变量引用与等式比较,c++,boost,boost-variant,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; } 因为在类known_get中选择了错误的运算符函数调用重载,所以不能比较非常量引用变

以下程序中止:

#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;
}
因为在类known_get中选择了错误的运算符函数调用重载,所以不能比较非常量引用变量之间的相等性。known_get在comparer visitor中被实例化为const T,而不是看起来应该是T的内容(v1.59.0中的variant.hpp:905)


我遗漏了什么吗?

好的,我对此进行了思考(并再次查看了文档)

boost::variant的概要没有显示为变量定义的运算符==

这使我认为正确的比较方法是通过二进制访问者

这是你的(修改过的)代码,它在我的机器上编译(苹果叮当声)。你的代码也使我的编译器崩溃了

#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;
}
#包括
#包括
使用variant_type=boost::variant;
结构是相等的
{
//比较int与int
布尔运算符(){
返回l==r;
}
//将字符串与字符串进行比较
布尔运算符()(常数std::string&l,常数std::string&r)常数{
返回l==r;
}
//其他任何东西与其他任何东西相比都是假的。
模板
布尔运算符()(常数X&,常数Y&)常数{
返回false;
}
};
int main(){
int a=0,b=0;
变量类型v=a,u=b;
bool ok=boost::apply_visitor(is_equal(),v,u);
//布尔ok=(v==u);
返回0;
}

我认为这是一个Boost bug

以下是:

  • 可复制的或可移动的
  • 析构函数支持无抛出异常安全保证
  • 在变量模板实例化点完成。(有关接受不完整类型以启用递归变量类型的类型包装,请参见
    boost::recursive_wrapper
以及:

  • 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);
}
使用
int&
,这些重载将变成:

const int& operator()(const int& ) const;
const int& operator()(int& ) const; [ U = int ]
第二个重载是首选的,因为它引用的类型比非模板重载的const-qualified更少。这就是为什么您会得到断言,而这种行为显然是不正确的。我们应该能够比较参考资料

更简单的解决方案是从
比较器
中删除
常量
s,只需使用:

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);
}
模板
布尔运算符()(T&rhs_内容)常量
{
已知的获得者;
T&lhs\u content=lhs\u.apply\u访问者(getter);
返回Comp()(左侧内容、右侧内容);
}

这将适用于引用类型以及
const
类型

我在boost文档中看不到任何关于引用变体的信息。那么乌布?我不这么认为。虽然docs和esp是真的。教程中没有提到存储引用,但使用这些引用的变体似乎没有任何障碍。Richard,在variant.hpp标头的第2236行定义了一个运算符==。如果那个操作员不在,我也会实施你的解决方案。现在我把这个失败归因于一个可能的错误,因为如果在variant.hpp的第905行将const T更改为known_get的模板参数列表中的T,代码编译并运行正常。同意如果操作符==应该是公共接口的一部分,那么它看起来就像一个错误。令人惊讶的是,它同时使clang和gcc崩溃:)是的,我的担心是我遗漏了一些明显的东西,关于为什么known_get被实例化为const T而不是T。我将尝试用boost提交一个bug,然后返回投票。
const int& operator()(const int& ) const;
const int& operator()(int& ) const; [ U = int ]
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);
}