我试图巢提升的" map_list_of"在C ++ 03,但显然建设是暧昧? [英] I'm trying to nest boost's "map_list_of" in C++03, but apparently construction is ambiguous?
问题描述
考虑一下:
的#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>
对(常量对< _U1,_U2>&安培; __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 ofmap_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 ageneric_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 bothmap
andCompare
. 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 innergeneric_list
to construct the outermap
. Dereferencing this iterator yields astd::pair<int, boost::assign_detail::generic_list<std::pair<int, char> >
. The node (value) type of the outer map isstd::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]p1template<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 onstd::is_convertible<U, T>::value
is not redundant, because it is possible to create types that can be copy-initialized but not direct-initializedThis is exactly the case we run into here: A
map
can be copy-initialized from ageneric_list
, since this makes theexplicit
constructor non-viable. But amap
cannot be direct-initialized fromgeneric_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 ofgeneric_list
's base classconverter
(also a class template):map_list_of(1, 'a')(2, 'b').convert_to_container<InnerMap>()
这篇关于我试图巢提升的&QUOT; map_list_of&QUOT;在C ++ 03,但显然建设是暧昧?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!