为什么不用boost :: tie和BOOST_FOREACH? [英] Why doesn't ::boost::tie work with BOOST_FOREACH?

查看:240
本文介绍了为什么不用boost :: tie和BOOST_FOREACH?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想用 BOOST_FOREACH 遍历一个 boost :: ptr_map ,并碰到这个整洁的解决方案。我宁愿使用这个更好的可读性,而不是其他的解决方案。我写了下面的代码:

  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<<一个<<两个<的std :: ENDL;





$ b然而,这个编译失败,并给我下面的错误(完整):

 错误:'operator = no'匹配错误消息有几行,让我知道是否应该粘贴它们。 (操作数类型是boost :: tuples :: detail :: tie_mapper< int,std :: basic_string< char> *,void,void,void,void,void,void> :: type {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>}'和'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 ++ version:4.8.4)

/ p>

解决方案

这个问题真的应该是为什么不是 boost :: tie 使用 boost :: ptr_map (或者是取消引用其迭代器的结果)? - BOOST_FOREACH 在这一切中都是相当无辜的。

调查



如果我们查看 Boost版本历史记录,我们可以看到 Tuple 出现在版本1.24.0和指针容器在版本1.33.0中。


$ b

元组



github中的相关元组相关代码: b
$ b



学习代码,我们可以做出如下观察:


  • tie 创建了一个元组
    [1]
    [2]

  • c $ c>元组
    总是从模板 cons
    [1]
    [2]


  • 元组(和 cons )总是有赋值运算符,一个 cons (ie另一个元组
    [1]
    [2]
    std :: pair
    [1]
    [2]
    - 其他都没有。



指针容器



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



研究代码,我们可以使以下是观察:


  • 在前两个版本(1.33.x)中,取消引用迭代器给了我们对 [1] ref_pair ,它看起来像 std :: pair ,但实际上不是
    [1 ]
    [2]
    [3]

  • >

    我们可以通过只执行一次迭代来消除 BOOST_FOREACH ,而仍然是g等同样的错误:

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

    根据我们之前的了解,我们知道这相当于

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

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



    由于元组没有赋值操作符,所以建议的代码片段不能用任何现有的Boost版本编译。






    解决方法



    从实现 boost :: tuple boost :: tie ,我们可以编写一个简单的 reference_pair 模板来存放两个引用,一个一对(即有成员第一个第二个),以及一个帮助程序 tie 函数,该函数将创建一个 reference_pair



    示例代码



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

    命名空间{

    模板< class T0,class T1>
    struct reference_pair
    {
    T0&第一;
    T1&第二;
    $ b 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;
    }
    };

    模板< class T0,class T1>
    inline reference_pair< T0,T1> (t 0,t 1,t 1,t 1,t 1,t 2,t 1,t 1,t 2)



    $ b 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;

    OOST_FOREACH(tie(one,two),int2strMap)
    {
    std :: cout<<一个<< << *两个<<的std :: ENDL;


    $ / code $ / pre
    $ b



    控制台输出

    h3>

      0 one 
    1 two
    2 three


    I want to use BOOST_FOREACH to iterate over a boost::ptr_map, and came across this neat-looking solution. I would prefer using this for better readability, as against the other solutions given. I wrote the following code:

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

    However, this fails to compile, and gives me the below error (The full error message has several more lines, let me know if I should paste them.):

    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)
    

    It appears that the suggested solution works for a handful of people, and I am unable to figure out why it doesn't work for me. What am I doing wrong here?

    (Note: I am working on a prehistoric project, so stuck with using C++03. g++ version: 4.8.4)

    解决方案

    The question really should be "Why doesn't boost::tie work with boost::ptr_map (or rather the result of dereferencing its iterator)?" -- BOOST_FOREACH is quite innocent in all this.

    Investigation

    If we look at the version history of Boost, we can see that Tuple appears in version 1.24.0 and Pointer Container in version 1.33.0.

    Tuple

    Relevant tuple related code in github:

    Studying the code, we can make the following observations:

    • tie has always created a tuple [1] [2]

    • tuple has always derived from template cons [1] [2]

    • tuple (and cons) always had assignment operators taking either a cons (i.e. another tuple) [1] [2] or a std::pair [1] [2] -- nothing else.

    Pointer Container

    Relevant pointer container related code in github:

    Studying the code, we can make the following observations:

    • In first two releases (1.33.x), dereferencing the iterator gave us a reference to the value [1] [2]
    • Since the third release (1.34.0), we get a ref_pair, which somewhat looks like a std::pair, but really isn't [1] [2] [3]

    Conclusion

    We can eliminate BOOST_FOREACH by just doing one iteration, and still get the same error:

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

    Based on what we learned earlier, we know this is equivalent to

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

    We also know that *int2strMap.begin() will result in either a std::string reference, or a ref_pair.

    Since tuple has no assignment operator that would take either of those, the proposed snippet can not compile with any existing version of Boost.


    Workaround

    Taking inspiration from the implementation of boost::tuple and boost::tie, we can write a simple reference_pair template that holds two references and allows assignment of anything that looks like a pair (i.e. has members first and second), along with a helper tie function that will create an instance of reference_pair.

    Sample Code

    #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

    Console Output

    0 one
    1 two
    2 three
    

    这篇关于为什么不用boost :: tie和BOOST_FOREACH?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆