c++ - 通过 boost 的递归对。自 boost 1.62 以来变体已损坏

标签 c++ boost boost-variant

我正在处理的代码使用递归对。在简化的示例中,该类型包含一对由 stringint 或另一对组成的对。这应该(并且已经)可以通过以下方式实现:

#include <boost/variant.hpp>
#include <string>

using namespace std;

typedef boost::make_recursive_variant
      < std::pair
        < std::string
        , boost::variant<int, boost::recursive_variant_>
        >
      >::type recursivePair;

typedef boost::variant< int
                    , recursivePair
                    > intPairVariant;

using sType = boost::variant<pair<string, string>, int>;

void foo(){
    sType bar(make_pair("aa", "bb"));
    recursivePair xxx(std::make_pair (std::string("s"), intPairVariant()));
    recursivePair yyy(std::make_pair (string("s"), 5));
    recursivePair zzz(std::make_pair ("s", 5));
}

sType 是为了表明该对中的隐式转换仍然适用。

但是从 Boost 1.62 开始,编译过程中会中断:

error: no matching function for call to ‘boost::variant<boost::detail::variant::recursive_flag<std::pair<std::__cxx11::basic_string<char>, boost::variant<int, boost::recursive_variant_> > > >::variant(std::pair<std::__cxx11::basic_string<char>, int>)’
     recursivePair yyy(std::make_pair (string("s"), 5));

这仅适用于一种类型。其他人也同样失败。

有谁知道为什么这不再有效以及如何解决这个问题?

最佳答案

我认为您实际上遇到了与 std::pair<> 类似的更改在这里看到:does boost-1.55 boost::property_tree::ptree compile with c++11?

自 c++11 以来,std::pair 的隐式转换较少。的确,您的代码确实编译了 boost < 1.62,但从本质上讲,这看起来是一个错误,至少在 c++11 模式下是这样。

在 C++11 中,你这样做:

std::make_pair(s, i); // s is std::string, i is int

结果为 std::pair<std::string, int> .接下来你不仅要求隐式转换 std::pair<std::string, int>std::pair<std::string, IntPairVariant> ,但您希望使用该转换的结果作为您正在分配的变体的初始值设定项。

在 C++ 的所有部分中,这都要求进行两次隐式转换,编译器永远不会使用它来解析重载。

因此,实际上您的代码有点草率,因为它使用了 Boost Variant 可能不应该有的“回旋余地”。它一个重大变化,但新行为似乎更有意义。

另一个注意事项

您正在使用单个元素制作递归变体。这……有点奇怪。

这通过隐藏 std::pair<> 对类型系统造成了不必要的“压力”。第一层下的结构特性variant .

使用 std::pair直接

Live On Coliru

我能想到的最无聊的事:

#include <boost/variant.hpp>
#include <string>

using namespace std;

typedef std::pair<std::string,
    boost::make_recursive_variant<int, std::pair<std::string, boost::recursive_variant_> >::type >
    recursivePair;

typedef boost::variant<int, recursivePair> intPairVariant;

int main() {
    recursivePair xxx(std::string("s"), intPairVariant());
    recursivePair yyy(string("s"), 5);
    recursivePair zzz("s", 5);
}

请注意,这已经允许您问题中的确切拼写:

recursivePair xxx(std::make_pair(std::string("s"), intPairVariant()));
recursivePair yyy(std::make_pair(string("s"), 5));
recursivePair zzz(std::make_pair("s", 5));

但是make_pair在这三种情况下都是多余的。

有趣的变化

也许你可以做些更像是

struct V;
using Pair = std::pair<std::string, V>;

struct V : boost::variant<int, boost::recursive_wrapper<Pair> > {
    using base = boost::variant<int, boost::recursive_wrapper<Pair> >;
    using base::base;
    using base::operator=;
};

现在你可以放心地说

Live On Coliru

Pair xxx("s", V{});
Pair yyy("s", 5);
Pair zzz{};

帮助构造器

使用派生结构而不是普通变体的好处是您实际上可以消除构造函数的歧义:

Live On Coliru

#include <boost/variant.hpp>
#include <string>
#include <iostream>

namespace mylib {

    struct V;
    using Pair = std::pair<std::string, V>;

    struct V : boost::variant<int, boost::recursive_wrapper<Pair> > {
        using base = boost::variant<int, boost::recursive_wrapper<Pair> >;

        V() = default;
        V(V&&) = default;
        V(V const&) = default;
        V& operator=(V&&) = default;
        V& operator=(V const&) = default;

        V(int i) : base(i) {}
        V(std::string const& key, V value);
    };

    V::V(std::string const& key, V value) : base{Pair{std::move(key), std::move(value)}} {}

    static inline std::ostream& operator<<(std::ostream& os, Pair const& p) {
        return os << "{" << p.first << "," << p.second << "}";
    }
}

int main() {
    using mylib::V;
    V xxx("s", mylib::V{});
    V yyy("s", 5);
    V zzz{};
    V huh("s", {"more", {"intricate", {"nested", { "truths", 42} } } });

    V simple = 5;
    simple = {"simple", 5};
    simple = {"not_so_simple", simple};

    std::cout << "xxx:" << xxx << "\n";
    std::cout << "yyy:" << yyy << "\n";
    std::cout << "zzz:" << zzz << "\n";
    std::cout << "huh:" << huh << "\n";
    std::cout << "simple:" << simple << "\n";
}

打印

xxx:{s,0}
yyy:{s,5}
zzz:0
huh:{s,{more,{intricate,{nested,{truths,42}}}}}
simple:{not_so_simple,{simple,5}}

关于c++ - 通过 boost 的递归对。自 boost 1.62 以来变体已损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49496103/

相关文章:

c++ - Google Mock 在尝试指定返回值时给出编译错误

c++ - 在 C++ 中使用 Boost-Python 访问 Python 中定义的函数数组

c++ - 带有 boost 变体的递归 using 声明

c++ - 我需要一个文本字段或 "Label vs TextField"

c++ - 愚蠢的语法错误 c++

java - 通过串行发送单独的信息

c++ - 二维数组 C++ 的列迭代器

c++ - VC++ 和 GCC 下 boost::condition_variable 的不同行为

c++ - 迭代 std::list<boost::variant>

c++ - 如何改变 boost::variant operator < 的行为