【问题标题】:boost::variant comparison with contained valueboost::variant 与包含值的比较
【发布时间】:2016-11-18 21:56:02
【问题描述】:

我正在尝试找到一种方法来比较 boost::variant 与基础值,而无需从该基础值构造变量。该问题在“main()”函数的注释中定义 辅助问题是关于代码中定义的比较运算符。如何减少比较运算符的数量?如果 boost::variant 包含 6 种不同的类型,我是否必须定义 6!运算符能够比较两个变体?

谢谢!

#include <boost/variant.hpp>
namespace test {

    namespace Tag {
        struct Level1{ int t{ 1 }; };
        struct Level2{ int t{ 2 }; };
    }

    template <typename Kind> struct Node;

    using LevelOne = Node<Tag::Level1>;
    using LevelTwo = Node<Tag::Level2>;

    using VariantNode = boost::variant
    <
        boost::recursive_wrapper<LevelOne>,
        boost::recursive_wrapper<LevelTwo>
    >;

    typedef VariantNode* pTree;
    typedef std::vector<pTree> lstTree;

    template <typename Kind> struct Node
    {
        Node(pTree p, std::string n) : parent(p), name(n) {}
        Node(const Node& another) : name(another.name), parent(another.parent) {}
        virtual ~Node() {}
        std::string name;
        pTree parent;
    };

    bool operator == (const LevelOne& one, const LevelTwo& two) {
        return false;
    }
    bool operator == (const LevelTwo& two, const LevelOne& one) {
        return false;
    }
    bool operator == (const LevelOne& one, const LevelOne& two) {
        return true;
    }
    bool operator == (const LevelTwo& one, const LevelTwo& two) {
        return true;
    }
}

int main(int argc, char *argv[])
{
    using namespace test;
    LevelOne l1(nullptr, "level one");
    VariantNode tl2 = VariantNode(LevelTwo(nullptr, "level two"));
    VariantNode tl1 = VariantNode(LevelOne(nullptr, "level one"));
    bool rv = (tl1 == tl2); // this line compiles OK (comparing two variants)
    // comparison below does not compile, because "l1" is not a variant. 
    // Question: How can I compare "variant" value "tl1" 
    // with one of the possible content values "l1"
    bool rv1 = (tl1 == l1); 
    return 1;
}

【问题讨论】:

  • 您的bool operator==(...) 可以模板化。其实不需要任何自定义模板魔法,直接返回std::is_same&lt;T1, T2&gt;::value即可。
  • @lorro - 谢谢!比较现在定义为: template bool operator == (const F& f, const S& s) { bool issame = std::is_same::value;如果(!issame)返回false;返回 f.name == s.name;剩下的问题 - 如何比较 boost::variant 和基础值而不用这个值构造变量?
  • 使用get&lt;&gt;()(如果我没听错的话)。
  • 使用 boost::get 我需要知道我正在比较变量的变量的类型。在邮政编码示例中,类型是 LevelOne,但我需要能够进行一般比较。例如,我需要将 boost::variant 类型的值与字符串或整数进行比较。
  • 你不需要知道类型,你可以再写一个模板。但是为它编写一个(模板化的)访问者可能更容易。

标签: c++ boost


【解决方案1】:

以下内容适用于变体中的任意数量的类型:

template<typename T>
struct equality_visitor : boost::static_visitor<bool> {
    explicit constexpr equality_visitor(T const& t) noexcept : t_{ &t } { }

    template<typename U, std::enable_if_t<std::is_same<T, U>::value>* = nullptr>
    constexpr bool operator ()(U const& u) const {
        return *t_ == u;
    }

    template<typename U, std::enable_if_t<!std::is_same<T, U>::value>* = nullptr>
    constexpr bool operator ()(U const&) const {
        return false;
    }

private:
    T const* t_;
};

template<
    typename T,
    typename... Ts,
    typename = std::enable_if_t<
        boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
    >
>
bool operator ==(T const& t, boost::variant<Ts...> const& v) {
    equality_visitor<T> ev{ t };
    return v.apply_visitor(ev);
}

template<
    typename T,
    typename... Ts,
    typename = std::enable_if_t<
        boost::mpl::contains<typename boost::variant<Ts...>::types, T>::value
    >
>
bool operator !=(T const& t, boost::variant<Ts...> const& v) {
    return !(t == v);
}

问题是比较必须始终采用value == variantvalue != variant 的形式,而不是variant == valuevariant != value。这是因为boost::variant&lt;&gt; 本身将这些运算符定义为始终为static_assert,我们无法让全局运算符比variant&lt;&gt; 的内置运算符更专业。

Online Demo

【讨论】:

  • @lidjarn - 谢谢!它在 vs2013 中编译和运行(没有 constexpr )。我没有使用可变参数模板,所以我正在研究代码。大有帮助!
猜你喜欢
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 2019-12-28
  • 2020-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多