问题在于隐式转换。它不是从
int
到
std::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 )
更好。委员会认为要求用户将上面的第一个整数显式转换为 size_t
可能有些过分了。
C++11 在这里进行了重大改变,并且:
std::vector<int, std::vector<int>> v2D( 10, 42 );
已不再合法。
至少我所看到的,std::pair
的构造函数没有应用任何此类更改。