我试图巢提升的" map_list_of"在C ++ 03,但显然建设是暧昧? [英] I'm trying to nest boost's "map_list_of" in C++03, but apparently construction is ambiguous?

查看:351
本文介绍了我试图巢提升的" map_list_of"在C ++ 03,但显然建设是暧昧?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一下:

 的#include<&iostream的GT;
#包括LT&;地图和GT;
#包括LT&;串GT;
#包括LT&;升压/转让/ list_of.hpp>
使用boost ::分配:: map_list_of;常量的std ::地图< INT,性病::地图< INT,CHAR和GT; >测试= map_list_of
    (100,map_list_of
        (1,'a')的
        (2,'B')
    )
    (101,map_list_of
        (1,'C')
        (2,'D')
    )
;诠释的main()
{
    性病::法院LT&;< test.find(101) - GT; second.find(2) - GT;二<< \\ n;
}

我想要的结果是一个程序,在执行时,输出 D

相反,我得到这个

  $铛++ -std = C ++ 03 -O2 -Wall -pedantic -pthread的main.cpp1:在文件main.cpp中,从包括:
在文件从/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/包括iostream的:39:
在文件从/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/包括ostream的:38:
在文件从/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/包括IOS:40:
在文件中包含来自/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/char_traits.h:39:
在文件中包含来自/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_algobase.h:64:
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_pair.h:119:22:错误:调用的'的std ::地图&LT构造,INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > >'不明确
        :第一个(__ p.first),第二(__ p.second){}
                            ^ ~~~~~~~~~~
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_tree.h:1843:29:注意:在函数模板特殊化'的std ::对&LT的实例; const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > > > ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > >'这里要求
          _M_insert_unique_(端(),* __第一);
                                   ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:255:16:注意:在函数模板特殊化'的std实例:: _ Rb_tree< INT,性病::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > >中的std :: _ Select1st<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > > > >中的std ::以下< INT>中的std ::分配器<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > > > > :: _ M_insert_unique<的std :: _ Deque_iterator<的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > >中的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > &放;,的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > *> >'这里要求
        {_M_t._M_insert_unique(__第一,__last); }
               ^
/usr/local/include/boost/assign/list_of.hpp:163:20:注意:在函数模板特殊化'的std ::地图&LT的实例;整型,性病::地图< INT,CHAR的std ::以下< INT&GT ;,性病::分配器<的std ::对< const int的,字符> > >中的std ::以下< INT>中的std ::分配器<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > > > > ::地图<的std :: _ Deque_iterator<的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > >中的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > &放;,的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > *> >'这里要求
            返回容器(开头(),结束());
                   ^
/usr/local/include/boost/assign/list_of.hpp:142:20:注意:在函数模板特殊化'的boost :: assign_detail ::转换器和LT的实例;提高:: assign_detail :: generic_list<的std ::对< INT ,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > >中的std :: _ Deque_iterator<的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > >中的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > &放;,的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > *> > ::转换<的std ::地图< INT,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > >中的std ::以下< INT>中的std ::分配器<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > > > > >'这里要求
            返回转换<集装箱>(三,TAG_TYPE());
                   ^
/usr/local/include/boost/assign/list_of.hpp:436:49:注意:在函数模板特殊化'的boost :: assign_detail ::转换器和LT的实例;提高:: assign_detail :: generic_list<的std ::对< INT ,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > >中的std :: _ Deque_iterator<的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > >中的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > &放;,的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > > *> > :: convert_to_container<的std ::地图< INT,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > >中的std ::以下< INT>中的std ::分配器<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > > > > >'这里要求
            返回这个 - > BOOST_NESTED_TEMPLATE convert_to_container<集装箱>();
                                                ^
main.cpp中:7:50:注意:在函数模板特殊化'助推实例:: assign_detail :: generic_list<的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR> > > > ::运算地图<的std ::地图< INT,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对< const int的,字符> > >中的std ::以下< INT>中的std ::分配器<的std ::对< const int的,性病::地图< INT,CHAR的std ::以下< INT>中的std ::分配器<的std ::对&LT ; const int的,字符> > > > > > >'这里要求
常量的std ::地图< INT,性病::地图< INT,CHAR和GT; >测试= map_list_of
                                                 ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:171:7:注意:考生构造
      地图(常量_Compare&放大器; __comp,
      ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:182:7:注意:考生构造
      地图(常量地图&安培; __X)
      ^
产生1个错误。

(下GCC类似的结果)

我怎样才能解决这个问题?

我得到的,即使我用一个类似的错误的std ::地图< INT,CHAR>(map_list_of(...))而不是 map_list_of(...)对于那些内部地图。


解决方案

C ++ 03定义了两个构造函数地图可与一个参数[lib.map被称为] P2:


 明确的地图(常量比较和放大器;可比=比较()
             常量分配器和放大器; =分配器());
// [...]
地图(常量地图<关键,T,比较,分配器>&安培; X);


升压的 map_list_of 创建一个 generic_list 类模板实例化的对象,从近期SVN:


 模板<重点类,类T>
内嵌assign_detail :: generic_list<性病::对
    <
        BOOST_DEDUCED_TYPENAME assign_detail :: assign_decay<关键> ::类型,
        BOOST_DEDUCED_TYPENAME assign_detail :: assign_decay< T> ::类型
    > >
map_list_of(const的重点和放大器; K,常量T& T公司)


其中主 generic_list 模板包含以下转换操作符:


 模板<一流的集装箱>
运营商集装箱()const的
{
    返回这个 - > BOOST_NESTED_TEMPLATE convert_to_container<集装箱>();
}


两者地图构造函数是可行的,因为该运营商可以转换到两个地图比较。据我所知,你不能SFINAE-限制在一个转换操作符C ++ 03。


地图构造的明确的插入在的地图新的节点时。一对迭代器用于遍历内 generic_list 来构造外地图。取消引用此迭代器产生一个的std ::对< INT,提振:: assign_detail :: generic_list<的std ::对< INT,CHAR和GT; > 。节点(值)型外图的是的std ::对< INT常量,性病::地图< INT,CHAR和GT;方式>

因此​​,编译器尝试构建从前者后者类型。在C ++ 03,这构造不SFINAE受限,因为在C ++中03是不可能的。 [lib.pairs] P1


 模板<类U,V类>对(常量对< U,V>&安培; P);


++的libstdc实现此如下:

 模板<类_U1,类_U2&G​​T;
  对(常量对< _U1,_U2&G​​T;&安培; __P)
  :第一个(__ p.first),第二(__ p.second){}

我不完全知道这是兼容的,因为[lib.pairs] P4


  

效果:从初始化参数的相应成员成员,需要进行隐式转换


(但是,正如我所说,在SFINAE构建函数不能在C ++ 03实现的。)

在C ++ 11和14,这也失败了,但出于不同的原因。在这里,对构造函数SFINAE受限。但约束需要的隐兑换的( is_convertible ),而程序具有UB如果目标对的类型不能<青霉>构造从源( is_constructible )。我已经写了一点关于这个问题另一SO回答。有趣的是,提出的解决方案 N4387 以在其他问题中提到的问题,说:


  

这里应注意的是,对于一般情况的
  的std :: is_constructible&LT; T,U&GT; ::值为无明确要求
  构造函数是在约束的std :: is_convertible&LT; U,T&GT; ::值
  不是多余的,因为它可以创建的类型,可以是
  复制初始化,但不直接初始化


这正是我们碰上这里的情况:A 地图可从复制初始化的 generic_list ,因为这使得明确构造非可行的。但地图无法从 generic_list 直接初始化,因为这使得转换模棱两可。

据我所看到的,N4387并没有解决在OP的问题。在另一方面,统一初始化,我们必须 map_list_of 的替代品。我们可以SFINAE-约束转换运营商,因为C ++ 11。


一个解决办法是只允许隐式转换,以消除明确构造器:

 模板&LT; typename的T&GT; ŧimplicit_cast(T T){返回吨; }implicit_cast&所述; InnerMap&GT;(map_list_of(1,'一个')(2,'B'))

但还有一个更直接的方式:只需使用 generic_list 的基类的 convert_to_container 成员函数转换(也是一类模板):

  map_list_of(1,'A')(2,'B')convert_to_container&LT; InnerMap&GT;()

Consider this:

#include <iostream>
#include <map>
#include <string>
#include <boost/assign/list_of.hpp>
using boost::assign::map_list_of;

const std::map<int, std::map<int, char> > test = map_list_of
    (100, map_list_of
        (1, 'a')
        (2, 'b')
    )
    (101, map_list_of
        (1, 'c')
        (2, 'd')
    )
;

int main()
{
    std::cout << test.find(101)->second.find(2)->second << "\n";
}

I wanted the result to be a program that, when executed, outputs d.

Instead, I get this:

$ clang++ -std=c++03 -O2 -Wall -pedantic -pthread main.cpp

In file included from main.cpp:1:
In file included from /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/iostream:39:
In file included from /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/ostream:38:
In file included from /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/ios:40:
In file included from /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/char_traits.h:39:
In file included from /usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_algobase.h:64:
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_pair.h:119:22: error: call to constructor of 'std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > >' is ambiguous
        : first(__p.first), second(__p.second) { }
                            ^      ~~~~~~~~~~
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_tree.h:1843:29: note: in instantiation of function template specialization 'std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > >::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > >' requested here
          _M_insert_unique_(end(), *__first);
                                   ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:255:16: note: in instantiation of function template specialization 'std::_Rb_tree<int, std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > >, std::_Select1st<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > >, std::less<int>, std::allocator<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > > >::_M_insert_unique<std::_Deque_iterator<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > >, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > &, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > *> >' requested here
        { _M_t._M_insert_unique(__first, __last); }
               ^
/usr/local/include/boost/assign/list_of.hpp:163:20: note: in instantiation of function template specialization 'std::map<int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > >, std::less<int>, std::allocator<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > > >::map<std::_Deque_iterator<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > >, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > &, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > *> >' requested here
            return Container( begin(), end() );
                   ^
/usr/local/include/boost/assign/list_of.hpp:142:20: note: in instantiation of function template specialization 'boost::assign_detail::converter<boost::assign_detail::generic_list<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > >, std::_Deque_iterator<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > >, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > &, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > *> >::convert<std::map<int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > >, std::less<int>, std::allocator<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > > > >' requested here
            return convert<Container>( c, tag_type() );
                   ^
/usr/local/include/boost/assign/list_of.hpp:436:49: note: in instantiation of function template specialization 'boost::assign_detail::converter<boost::assign_detail::generic_list<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > >, std::_Deque_iterator<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > >, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > &, std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > *> >::convert_to_container<std::map<int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > >, std::less<int>, std::allocator<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > > > >' requested here
            return this-> BOOST_NESTED_TEMPLATE convert_to_container<Container>();
                                                ^
main.cpp:7:50: note: in instantiation of function template specialization 'boost::assign_detail::generic_list<std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> > > >::operator map<std::map<int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > >, std::less<int>, std::allocator<std::pair<const int, std::map<int, char, std::less<int>, std::allocator<std::pair<const int, char> > > > > > >' requested here
const std::map<int, std::map<int, char> > test = map_list_of
                                                 ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:171:7: note: candidate constructor
      map(const _Compare& __comp,
      ^
/usr/local/bin/../lib/gcc/x86_64-unknown-linux-gnu/4.9.2/../../../../include/c++/4.9.2/bits/stl_map.h:182:7: note: candidate constructor
      map(const map& __x)
      ^
1 error generated.

(similar results under GCC)

How can I resolve this?

I get a similar error even if I use std::map<int, char>(map_list_of(...)) instead of map_list_of(...) for those inner maps.

解决方案

C++03 defines two constructors for map that can be called with one argument [lib.map]p2:

explicit map(const Compare& comp = Compare(),
             const Allocator& = Allocator());
// [...]
map(const map<Key,T,Compare,Allocator>& x);

boost's map_list_of creates an object of a generic_list class template instantiation, from the recent SVN:

template< class Key, class T >
inline assign_detail::generic_list< std::pair
    < 
        BOOST_DEDUCED_TYPENAME assign_detail::assign_decay<Key>::type, 
        BOOST_DEDUCED_TYPENAME assign_detail::assign_decay<T>::type
    > >
map_list_of( const Key& k, const T& t )

Where the primary generic_list template contains the following conversion operator:

template< class Container >
operator Container() const
{
    return this-> BOOST_NESTED_TEMPLATE convert_to_container<Container>();
}

Both map constructors are viable, as this operator allows conversion to both map and Compare. As far as I know, you cannot SFINAE-constrain a conversion operator in C++03.


The map is constructed explicitly when inserting a new node in the outer map. A pair of iterators is used to iterate over the inner generic_list to construct the outer map. Dereferencing this iterator yields a std::pair<int, boost::assign_detail::generic_list<std::pair<int, char> >. The node (value) type of the outer map is std::pair<int const, std::map<int, char> >.

Therefore, the compiler tries to construct the latter type from the former. In C++03, this pair constructor is not SFINAE-constrained, since that's not possible in C++03. [lib.pairs]p1

template<class U, class V> pair(const pair<U, V> &p);

libstdc++ implements this as follows:

template<class _U1, class _U2>
  pair(const pair<_U1, _U2>& __p)
  : first(__p.first), second(__p.second) { }

I'm not entirely sure if that's compliant, since [lib.pairs]p4

Effects: Initializes members from the corresponding members of the argument, performing implicit conversions as needed.

(But, as I said, SFINAE on ctors cannot be implemented in C++03.)

In C++11 and 14, this also fails, but for a different reason. Here, the pair constructors are SFINAE-constrained. But the constrain requires implicit convertibility (is_convertible), while the program has UB if the target pair of types cannot be constructed from the sources (is_constructible). I've written a bit more about this issue in another SO answer. Interestingly, a proposed solution N4387 to the issue mentioned in that other question says:

It should be noted here, that for the general case the std::is_constructible<T, U>::value requirement for the non-explicit constructor which is constrained on std::is_convertible<U, T>::value is not redundant, because it is possible to create types that can be copy-initialized but not direct-initialized

This is exactly the case we run into here: A map can be copy-initialized from a generic_list, since this makes the explicit constructor non-viable. But a map cannot be direct-initialized from generic_list, since this makes the conversion ambiguous.

As far as I can see, N4387 does not solve the problem in the OP. On the other hand, with uniform initialization, we have an alternative to map_list_of. And we can SFINAE-constrain conversion operators since C++11.


One solution is to eliminate the explicit constructor by only allowing implicit conversions:

template<typename T> T implicit_cast(T t) { return t; }

implicit_cast<InnerMap>( map_list_of(1, 'a')(2, 'b') )

But there's a more direct way: simply use the convert_to_container member function of generic_list's base class converter (also a class template):

map_list_of(1, 'a')(2, 'b').convert_to_container<InnerMap>()

这篇关于我试图巢提升的&QUOT; map_list_of&QUOT;在C ++ 03,但显然建设是暧昧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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