为什么 std::pair 在赋值中调用显式构造函数
考虑以下代码:
#include<iostream>
#include<utility>
struct Base
{
int baseint;
};
struct Der1 : Base
{
int der1int;
Der1() : der1int(1) {}
explicit Der1(const Base& a) : Base(a), der1int(1)
{
std::cerr << "cc1" << std::endl;
}
};
struct Der2 : Base
{
int der2int;
Der2() : der2int(2) {}
explicit Der2(const Base& a) : Base(a), der2int(2)
{
std::cerr << "cc2" << std::endl;
}
};
template <typename T, typename U>
struct MyPair
{
T first;
U second;
};
int main()
{
Der1 d1;
Der2 d2;
std::pair<Der1, int> p1;
std::pair<Der2, int> p2;
p1 = p2; // This compiles successfully
MyPair<Der1, int> mp1;
MyPair<Der2, int> mp2;
mp1 = mp2; // This will raise compiler error, as expected.
}
在 GCC 4.5.2 下测试
原因在于 std::pair
源:
/** There is also a templated copy ctor for the @c pair class itself. */
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }
该行为是否符合 C++ 标准?乍一看,它看起来不一致且违反直觉。 STL 的其他实现是否也以同样的方式工作?
Consider the following code:
#include<iostream>
#include<utility>
struct Base
{
int baseint;
};
struct Der1 : Base
{
int der1int;
Der1() : der1int(1) {}
explicit Der1(const Base& a) : Base(a), der1int(1)
{
std::cerr << "cc1" << std::endl;
}
};
struct Der2 : Base
{
int der2int;
Der2() : der2int(2) {}
explicit Der2(const Base& a) : Base(a), der2int(2)
{
std::cerr << "cc2" << std::endl;
}
};
template <typename T, typename U>
struct MyPair
{
T first;
U second;
};
int main()
{
Der1 d1;
Der2 d2;
std::pair<Der1, int> p1;
std::pair<Der2, int> p2;
p1 = p2; // This compiles successfully
MyPair<Der1, int> mp1;
MyPair<Der2, int> mp2;
mp1 = mp2; // This will raise compiler error, as expected.
}
Tested under GCC 4.5.2
The reason lies in std::pair
sources:
/** There is also a templated copy ctor for the @c pair class itself. */
template<class _U1, class _U2>
pair(const pair<_U1, _U2>& __p)
: first(__p.first),
second(__p.second) { }
Is that behaviour compliant with the C++ standard? For a first sight it looks inconsistent and counterintuitive. Do the other implementations of STL work the same way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不确定我是否理解这个问题,但基本上您是在问为什么两个不相关的 std::pair 可以隐式转换,即使实例化类型不可隐式转换。这就是为什么实例化类型的隐式可转换属性不会传播到该对。
该标准没有为 std::pair 模板提供显式赋值运算符,这意味着它将使用隐式生成的赋值运算符。为了能够分配可转换类型对,它依赖于模板化构造函数,该构造函数允许从
std::pair
到std 的隐式转换::pair
,其行为在 §20.2.2 [lib.pairs]/4 中定义该标准似乎只要求实现使用隐式转换,而在这个特定的实现中,转换实际上是显式的,这似乎与标准的措辞相矛盾。
I am not sure that I understand the question, but basically you are asking why two unrelated
std::pair
can be implicitly convertible even if the instantiating types are not implicitly convertible. That is, why the implicitly convertible property of the instantiating types does not propagate to the pair.The standard does not provide explicit assignment operators for the
std::pair
template, which means that it will use the implicitly generated assignment operator. To be able to assign pairs of convertible types, it relies on a templated constructor that allows an implicit conversion fromstd::pair<A,B>
tostd::pair<C,D>
, the behavior of which is defined in §20.2.2 [lib.pairs]/4The standard seems to only require the implementation to use implicit conversions, and in this particular implementation the conversion is actually explicit, which seems to contradict the wording of the standard.
作为类 std::pair 的一部分,构造函数
不是复制构造函数,而是从任何
pair<_U1, _U2>
到pair
的转换构造函数。这适用于first
和second
成员可转换为另一对的相应成员的情况。每个成员单独转换是根据标准进行的。
As part of class std::pair the constructor
is not a copy constructor, but a converting constructor from any
pair<_U1, _U2>
topair<T1, T2>
. This works for cases where thefirst
andsecond
members are convertible to the corresponding member of the other pair.Converting each member separately is according to the standard.
这确实应该是一条评论,但我更喜欢有一些空间来写出来。
所以,假设我们有两种类型:
现在我想将一种类型分配给另一种类型:
由于
std::pair
没有显式赋值运算符,因此我们只能使用默认赋值对AB &运算符=(常量pairAB&amp;)
。因此,我们调用隐式转换构造函数,这相当于:但是,已经指出,此转换构造函数调用显式成员构造函数:
因此,对于每个成员,我们分别一定要使用显式转换。
This should really be a comment, but I prefer some room to type this out.
So, lets say we have two types:
Now I want to assign one to the other:
Since
std::pair
doesn't have an explicit assigment operator, we can only use the default assignmentpairAB & operator=(const pairAB &)
. Thus we invoke the implicit conversion constructor, which is equivalent to:However, has has been pointed out, this conversion constructor calls the explicit member constructors:
Thus for each member individually we do use explicit conversion.
快速回答:因为标准说应该这样做。
当然,您的下一个问题是:为什么标准这么说?
想象一下这一行,我认为你同意它应该起作用:
但是由于
3
和5
是整数,我们试图分配一个std::pair
到std::pair
。如果没有模板化构造函数和模板化赋值运算符,它将失败,正如您的MyPair
所证明的那样。所以回答你的问题:模板化构造函数是为了方便。每个人都希望能够将 int 分配给 long。因此,能够将一对 int 分配给一对 long 是合理的。
Quick answer: Because the standard says it should.
Your next question, of course, will be: Why does the standard say so?
Imagine this line, which I think you agree should work:
But as
3
and5
are ints, we are trying to assign astd::pair<int, int>
to astd::pair<long, long>
. Without a templated constructor and a templated assignment operator, it would fail, as yourMyPair
proved.So to answer your question: the templated constructor is for convenience. Everyone expects to be able to assign an int to a long. So it is reasonable to be able to assign e.g. a pair of ints to a pair of longs.