std::map的密钥出现问题



请考虑以下代码。由integer和integer的向量组成的元组被定义为映射的键。然而,我感到惊讶的是,编译器在插入或查找由integer和integer组成的元组作为键时没有抛出任何错误。既然元组的第二个元素应该是integer向量类型,这怎么可能呢?

std::map <boost::tuple<int, vector<int > >, int> test;
std::map <boost::tuple<int, vector<int > >, int>::iterator test_it;
vector <int> t;
t.push_back(4);
test.insert(make_pair(boost::make_tuple(3, t), 4));
test.insert(make_pair(boost::make_tuple(3, 6), 4));
test_it = test.find(boost::make_tuple(3, 7)); 
if(test_it != test.end()) 
throw " test is passed";  

看起来像是Boost和许多C++标准库实现中的一个bug。pairtuple都有这个问题。演示它的最简单代码是:

#include <vector>
#include <utility>
using namespace std;
int main() {
    //compiles
    pair<int,vector<int>> bug1( pair<int,int>(5,6) );
    //compiles
    pair<int,vector<int>> bug2;
    bug2 = pair<int,int>(5,6);
}

libc++敲4.0,另一个接受这个,Comeau Online也接受。GCC 4.7.1给出了一个错误。

它不能编译,根据:

20.3.2/12

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

备注:除非const U&隐式地可转换为first_type和const V&隐式转换为second_type。

20.3.2/23

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

要求:is_assignable<first_type&, const U&>::valuetrueis_assignable<second_type&, const V&>::valuetrue

问题在于隐式转换。不是从intstd::vector<int>;这是行不通的,因为构造函数存在声明的explicit,因此不能用于隐式转换。隐式转换是从std::pair<int, int>std::pair<int, std::vector<int> >。这使用派生的构造函数来自模板:template <typename U1, typename U2> std::pair( std::pair<U1, U2> const& ),这不是隐式的。以及定义这个构造函数的是:

template <typename T1, typename T2>
template <typename U1, typename U2>
std::pair<T1, T2>::std::pair( std::pair<U1, U2> const& other )
    : first( other.first )
    , second( other.second )
{
}

(标准并不是这样规定的C++03中的规范不允许有太多其他内容。在C++11中,有很多额外的行李,以便在可能的情况下可以移动,但我认为最终的效果是一样的。)

请注意,在这个构造函数中,有一个显式调用构造函数,而不是隐式转换。所以对于隐含的将pair转换为功就足够了明确可转换。

就我个人而言,我怀疑这是否是最初的意图。我怀疑,在事实上,围绕std::pair的大部分语言都被冻结了在explicit被添加到该语言之前,所以没有问题。后来,没有人想过要重新讨论这个问题。在C++11中,重新审视它会破坏向后兼容性。所以你会得到一些意想不到的东西转换。

请注意,这并不是转发导致显式转换为隐式。考虑:

std::vector<std::vector<int> > v2D( 5, 10 );

显然,10不是std::vector<int>(第二个参数应该是)。但是在C++03中,这与构造函数匹配模板:

template<typename ForwardIterator, typename ForwardIterator>
std::vector( ForwardIterator begin, ForwardIterator end );

该标准对此有一些特殊的语言:

--构造函数

template <class InputIterator>
X(InputIterator f, InputIterator l, const Allocator& a = Allocator())

应具有与相同的效果

X(static_cast<typename X::size_type>(f),
static_cast<typename X::value_type>(l), a)

如果InputIterator是整型。

而隐含的转换已经变成了显性的。

(注意,如果没有这种特殊语言,

std::vector<int> v(10, 42);

编译失败:上面的模板构造函数的实例,是一个精确匹配,这比std::vector<int>( size_t, int )要好。委员会认为,需要对第一个上面的integer对size_t的要求可能太高了。)

C++11已经显著地改变了这里的措辞,并且:

std::vector<int, std::vector<int>> v2D( 10, 42 );

不再合法。

据我所见,没有对CCD_ 21的构造函数。

相关内容

  • 没有找到相关文章

最新更新