问题是隐式转换。不是从int
到
std::vector<int>
; 那是行不通的,因为那里涉及的构造函数是声明explicit
的,因此不能用于隐式转换。隐式转换是 fromstd::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
不是 a 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
.