【问题标题】:Why doesn't ::boost::tie work with BOOST_FOREACH?为什么 ::boost::tie 不能与 BOOST_FOREACH 一起使用?
【发布时间】:2017-06-16 11:52:41
【问题描述】:

我想使用BOOST_FOREACH 来迭代boost::ptr_map,然后遇到this neat-looking solution。与给出的其他解决方案相比,我更喜欢使用它以获得更好的可读性。我写了以下代码:

boost::ptr_map<int, std::string> int2strMap;
int x = 1;
int2strMap.insert(x, new std::string("one"));
int one;
std::string* two;
BOOST_FOREACH(::boost::tie(one, two), int2strMap)
{
   std::cout << one << two << std::endl;
}

但是,这无法编译,并给我以下错误(完整的错误消息还有几行,如果我应该粘贴它们,请告诉我。):

error: no match for 'operator=' (operand types are 'boost::tuples::detail::tie_mapper<int, std::basic_string<char>*, void, void, void, void, void, void, void, void>::type {aka boost::tuples::tuple<int&, std::basic_string<char>*&, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type, boost::tuples::null_type>}' and 'boost::iterators::iterator_reference<boost::ptr_map_iterator<std::_Rb_tree_iterator<std::pair<const int, void*> >, int, std::basic_string<char>* const> >::type {aka boost::ptr_container_detail::ref_pair<int, std::basic_string<char>* const>}')
BOOST_FOREACH(::boost::tie(one, two), int2strMap)

建议的解决方案似乎适用于少数人,但我无法弄清楚为什么它不适合我。我在这里做错了什么?

(注意:我正在做一个史前项目,所以坚持使用 C++03。g++ 版本:4.8.4)

【问题讨论】:

  • 如果不检查胆量就不能确定,但​​这可能与您不能使用std::tuple 执行此操作的原因相同。它只能使用编译时构造进行迭代。
  • 我怀疑这个看起来整洁的解决方案是否可行,因为它希望迭代器给我们一个std::pair,但我们只得到kinda looks like it的东西。 (自发布该答案以来,代码似乎没有更改)
  • 但是,您可以实现自己的简单 tie 等价物 -- like this
  • @Dan 这当然是一种可能性,但我希望 7 个人不会在不检查它是否正确的情况下投票。嗯……
  • @MaskedMan 在对提升报告进行了更多挖掘之后,我确信它永远不会起作用。至于你说的话,这很可悲,但是在看到大量对完全垃圾的支持以及无数各种懒惰的例子后,我倾向于对选票持保留态度——尤其是当答案没有任何参考资料时,工作(最好是现场)样本等

标签: c++ boost foreach c++03


【解决方案1】:

问题应该是“为什么boost::tie 不能与boost::ptr_map 一起工作(或者更确切地说是取消引用其迭代器的结果)?” -- BOOST_FOREACH 在这一切中都是无辜的。

调查

如果我们查看version history of Boost,我们可以看到 Tuple 出现在 1.24.0 版本中,Pointer Container 出现在 1.33.0 版本中。

元组

github中相关元组相关代码:

研究代码,我们可以做出以下观察:

  • tie 始终创建一个 tuple [1] [2]

  • tuple 始终派生自模板 cons [1] [2]

  • tuple(和cons)总是有赋值运算符采用cons(即另一个tuple[1] [2]std::pair [1] [2] -- 没有别的。

指针容器

github中相关指针容器相关代码:

研究代码,我们可以做出以下观察:

  • 在前两个版本 (1.33.x) 中,取消引用迭代器为我们提供了对值 [1] [2] 的引用
  • 自第三版 (1.34.0) 以来,我们得到了一个 ref_pair,它有点像 std::pair,但实际上不是 [1] [2] [3]

结论

我们可以通过只进行一次迭代来消除BOOST_FOREACH,但仍然会得到相同的错误:

boost::tie(one, two) = *int2strMap.begin();

根据我们之前所学,我们知道这相当于

boost::tuple<int&, std::string*&>(one, two) = *int2strMap.begin();

我们也知道*int2strMap.begin() 将导致std::string 引用或ref_pair

由于元组没有可以接受其中任何一个的赋值运算符,因此建议的 sn-p 无法与任何现有版本的 Boost 一起编译。


解决方法

boost::tupleboost::tie 的实现中获得灵感,我们可以编写一个简单的reference_pair 模板,它包含两个引用并允许分配任何看起来像pair 的东西(即有成员firstsecond),以及一个帮助器 tie 函数,它将创建一个 reference_pair 的实例。

示例代码

#include <boost/ptr_container/ptr_map.hpp>
#include <boost/foreach.hpp>
#include <iostream>

namespace {

template<class T0, class T1>
struct reference_pair
{
    T0& first;
    T1& second;

    reference_pair(T0& t0, T1& t1) : first(t0), second(t1) {}

    template<class U>
    reference_pair& operator=(const U& src) {
        first = src.first;
        second = src.second;
        return *this;
    }
};

template<class T0, class T1>
inline reference_pair<T0, T1> tie(T0& t0, T1& t1)
{
    return reference_pair<T0, T1>(t0, t1);
}

}

int main()
{
    boost::ptr_map<int, std::string> int2strMap;
    int n(0);
    int2strMap.insert(n, new std::string("one"));
    int2strMap.insert(++n, new std::string("two"));
    int2strMap.insert(++n, new std::string("three"));

    int one;
    std::string* two;

    BOOST_FOREACH(tie(one, two), int2strMap)
    {
       std::cout << one << " " << *two << std::endl;
    }
}

Live on Coliru

控制台输出

0 one
1 two
2 three

【讨论】:

    猜你喜欢
    • 2021-12-25
    • 2012-12-05
    • 2012-12-02
    • 1970-01-01
    • 2010-10-22
    • 2018-03-09
    • 2021-06-14
    • 2012-10-09
    • 2020-03-18
    相关资源
    最近更新 更多